mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts: sound/core/memalloc.c
This commit is contained in:
commit
56c5d900db
3711 changed files with 190539 additions and 88192 deletions
|
|
@ -130,12 +130,12 @@ static const char filename[] = __FILE__;
|
|||
|
||||
static const char timeout_msg[] = "*** timeout at %s:%s (line %d) ***\n";
|
||||
#define TIMEOUT_MSG(lineno) \
|
||||
printk(timeout_msg, filename,__FUNCTION__,(lineno))
|
||||
printk(timeout_msg, filename,__func__,(lineno))
|
||||
|
||||
static const char invalid_pcb_msg[] =
|
||||
"*** invalid pcb length %d at %s:%s (line %d) ***\n";
|
||||
#define INVALID_PCB_MSG(len) \
|
||||
printk(invalid_pcb_msg, (len),filename,__FUNCTION__,__LINE__)
|
||||
printk(invalid_pcb_msg, (len),filename,__func__,__LINE__)
|
||||
|
||||
static char search_msg[] __initdata = KERN_INFO "%s: Looking for 3c505 adapter at address %#x...";
|
||||
|
||||
|
|
|
|||
|
|
@ -127,7 +127,6 @@ MODULE_PARM_DESC (multicast_filter_limit, "8139cp: maximum number of filtered mu
|
|||
(CP)->tx_tail - (CP)->tx_head - 1)
|
||||
|
||||
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
|
||||
#define RX_OFFSET 2
|
||||
#define CP_INTERNAL_PHY 32
|
||||
|
||||
/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */
|
||||
|
|
@ -552,14 +551,14 @@ rx_status_loop:
|
|||
printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d\n",
|
||||
dev->name, rx_tail, status, len);
|
||||
|
||||
buflen = cp->rx_buf_sz + RX_OFFSET;
|
||||
new_skb = dev_alloc_skb (buflen);
|
||||
buflen = cp->rx_buf_sz + NET_IP_ALIGN;
|
||||
new_skb = netdev_alloc_skb(dev, buflen);
|
||||
if (!new_skb) {
|
||||
dev->stats.rx_dropped++;
|
||||
goto rx_next;
|
||||
}
|
||||
|
||||
skb_reserve(new_skb, RX_OFFSET);
|
||||
skb_reserve(new_skb, NET_IP_ALIGN);
|
||||
|
||||
dma_unmap_single(&cp->pdev->dev, mapping,
|
||||
buflen, PCI_DMA_FROMDEVICE);
|
||||
|
|
@ -1051,19 +1050,20 @@ static void cp_init_hw (struct cp_private *cp)
|
|||
cpw8_f(Cfg9346, Cfg9346_Lock);
|
||||
}
|
||||
|
||||
static int cp_refill_rx (struct cp_private *cp)
|
||||
static int cp_refill_rx(struct cp_private *cp)
|
||||
{
|
||||
struct net_device *dev = cp->dev;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < CP_RX_RING_SIZE; i++) {
|
||||
struct sk_buff *skb;
|
||||
dma_addr_t mapping;
|
||||
|
||||
skb = dev_alloc_skb(cp->rx_buf_sz + RX_OFFSET);
|
||||
skb = netdev_alloc_skb(dev, cp->rx_buf_sz + NET_IP_ALIGN);
|
||||
if (!skb)
|
||||
goto err_out;
|
||||
|
||||
skb_reserve(skb, RX_OFFSET);
|
||||
skb_reserve(skb, NET_IP_ALIGN);
|
||||
|
||||
mapping = dma_map_single(&cp->pdev->dev, skb->data,
|
||||
cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ enum RTL8139_registers {
|
|||
Cfg9346 = 0x50,
|
||||
Config0 = 0x51,
|
||||
Config1 = 0x52,
|
||||
FlashReg = 0x54,
|
||||
TimerInt = 0x54,
|
||||
MediaStatus = 0x58,
|
||||
Config3 = 0x59,
|
||||
Config4 = 0x5A, /* absent on RTL-8139A */
|
||||
|
|
@ -325,6 +325,7 @@ enum RTL8139_registers {
|
|||
FIFOTMS = 0x70, /* FIFO Control and test. */
|
||||
CSCR = 0x74, /* Chip Status and Configuration Register. */
|
||||
PARA78 = 0x78,
|
||||
FlashReg = 0xD4, /* Communication with Flash ROM, four bytes. */
|
||||
PARA7c = 0x7c, /* Magic transceiver parameter register. */
|
||||
Config5 = 0xD8, /* absent on RTL-8139A */
|
||||
};
|
||||
|
|
@ -1722,13 +1723,18 @@ static int rtl8139_start_xmit (struct sk_buff *skb, struct net_device *dev)
|
|||
}
|
||||
|
||||
spin_lock_irqsave(&tp->lock, flags);
|
||||
/*
|
||||
* Writing to TxStatus triggers a DMA transfer of the data
|
||||
* copied to tp->tx_buf[entry] above. Use a memory barrier
|
||||
* to make sure that the device sees the updated data.
|
||||
*/
|
||||
wmb();
|
||||
RTL_W32_F (TxStatus0 + (entry * sizeof (u32)),
|
||||
tp->tx_flag | max(len, (unsigned int)ETH_ZLEN));
|
||||
|
||||
dev->trans_start = jiffies;
|
||||
|
||||
tp->cur_tx++;
|
||||
wmb();
|
||||
|
||||
if ((tp->cur_tx - NUM_TX_DESC) == tp->dirty_tx)
|
||||
netif_stop_queue (dev);
|
||||
|
|
@ -2009,9 +2015,9 @@ no_early_rx:
|
|||
/* Malloc up new buffer, compatible with net-2e. */
|
||||
/* Omit the four octet CRC from the length. */
|
||||
|
||||
skb = dev_alloc_skb (pkt_size + 2);
|
||||
skb = netdev_alloc_skb(dev, pkt_size + NET_IP_ALIGN);
|
||||
if (likely(skb)) {
|
||||
skb_reserve (skb, 2); /* 16 byte align the IP fields. */
|
||||
skb_reserve (skb, NET_IP_ALIGN); /* 16 byte align the IP fields. */
|
||||
#if RX_BUF_IDX == 3
|
||||
wrap_copy(skb, rx_ring, ring_offset+4, pkt_size);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -1386,7 +1386,8 @@ config FORCEDETH_NAPI
|
|||
|
||||
config CS89x0
|
||||
tristate "CS89x0 support"
|
||||
depends on NET_PCI && (ISA || MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X)
|
||||
depends on NET_ETHERNET && (ISA || EISA || MACH_IXDP2351 \
|
||||
|| ARCH_IXDP2X01 || ARCH_PNX010X || MACH_MX31ADS)
|
||||
---help---
|
||||
Support for CS89x0 chipset based Ethernet cards. If you have a
|
||||
network (Ethernet) card of this type, say Y and read the
|
||||
|
|
@ -1397,6 +1398,11 @@ config CS89x0
|
|||
To compile this driver as a module, choose M here. The module
|
||||
will be called cs89x0.
|
||||
|
||||
config CS89x0_NONISA_IRQ
|
||||
def_bool y
|
||||
depends on CS89x0 != n
|
||||
depends on MACH_IXDP2351 || ARCH_IXDP2X01 || ARCH_PNX010X || MACH_MX31ADS
|
||||
|
||||
config TC35815
|
||||
tristate "TOSHIBA TC35815 Ethernet support"
|
||||
depends on NET_PCI && PCI && MIPS
|
||||
|
|
@ -1813,7 +1819,7 @@ config FEC2
|
|||
|
||||
config FEC_MPC52xx
|
||||
tristate "MPC52xx FEC driver"
|
||||
depends on PPC_MERGE && PPC_MPC52xx && PPC_BESTCOMM_FEC
|
||||
depends on PPC_MPC52xx && PPC_BESTCOMM_FEC
|
||||
select CRC32
|
||||
select PHYLIB
|
||||
---help---
|
||||
|
|
@ -1840,6 +1846,17 @@ config NE_H8300
|
|||
Say Y here if you want to use the NE2000 compatible
|
||||
controller on the Renesas H8/300 processor.
|
||||
|
||||
config ATL2
|
||||
tristate "Atheros L2 Fast Ethernet support"
|
||||
depends on PCI
|
||||
select CRC32
|
||||
select MII
|
||||
help
|
||||
This driver supports the Atheros L2 fast ethernet adapter.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called atl2.
|
||||
|
||||
source "drivers/net/fs_enet/Kconfig"
|
||||
|
||||
endif # NET_ETHERNET
|
||||
|
|
@ -1927,15 +1944,6 @@ config E1000
|
|||
To compile this driver as a module, choose M here. The module
|
||||
will be called e1000.
|
||||
|
||||
config E1000_DISABLE_PACKET_SPLIT
|
||||
bool "Disable Packet Split for PCI express adapters"
|
||||
depends on E1000
|
||||
help
|
||||
Say Y here if you want to use the legacy receive path for PCI express
|
||||
hardware.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config E1000E
|
||||
tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support"
|
||||
depends on PCI && (!SPARC32 || BROKEN)
|
||||
|
|
@ -2046,6 +2054,7 @@ config R8169
|
|||
tristate "Realtek 8169 gigabit ethernet support"
|
||||
depends on PCI
|
||||
select CRC32
|
||||
select MII
|
||||
---help---
|
||||
Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter.
|
||||
|
||||
|
|
@ -2262,7 +2271,7 @@ config UGETH_TX_ON_DEMAND
|
|||
config MV643XX_ETH
|
||||
tristate "Marvell Discovery (643XX) and Orion ethernet support"
|
||||
depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION
|
||||
select MII
|
||||
select PHYLIB
|
||||
help
|
||||
This driver supports the gigabit ethernet MACs in the
|
||||
Marvell Discovery PPC/MIPS chipset family (MV643XX) and
|
||||
|
|
@ -2281,12 +2290,13 @@ config QLA3XXX
|
|||
will be called qla3xxx.
|
||||
|
||||
config ATL1
|
||||
tristate "Attansic L1 Gigabit Ethernet support (EXPERIMENTAL)"
|
||||
depends on PCI && EXPERIMENTAL
|
||||
tristate "Atheros/Attansic L1 Gigabit Ethernet support"
|
||||
depends on PCI
|
||||
select CRC32
|
||||
select MII
|
||||
help
|
||||
This driver supports the Attansic L1 gigabit ethernet adapter.
|
||||
This driver supports the Atheros/Attansic L1 gigabit ethernet
|
||||
adapter.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called atl1.
|
||||
|
|
@ -2302,6 +2312,18 @@ config ATL1E
|
|||
To compile this driver as a module, choose M here. The module
|
||||
will be called atl1e.
|
||||
|
||||
config JME
|
||||
tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
|
||||
depends on PCI
|
||||
select CRC32
|
||||
select MII
|
||||
---help---
|
||||
This driver supports the PCI-Express gigabit ethernet adapters
|
||||
based on JMicron JMC250 chipset.
|
||||
|
||||
To compile this driver as a module, choose M here. The module
|
||||
will be called jme.
|
||||
|
||||
endif # NETDEV_1000
|
||||
|
||||
#
|
||||
|
|
@ -2377,10 +2399,18 @@ config EHEA
|
|||
To compile the driver as a module, choose M here. The module
|
||||
will be called ehea.
|
||||
|
||||
config ENIC
|
||||
tristate "E, the Cisco 10G Ethernet NIC"
|
||||
depends on PCI && INET
|
||||
select INET_LRO
|
||||
help
|
||||
This enables the support for the Cisco 10G Ethernet card.
|
||||
|
||||
config IXGBE
|
||||
tristate "Intel(R) 10GbE PCI Express adapters support"
|
||||
depends on PCI && INET
|
||||
select INET_LRO
|
||||
select INTEL_IOATDMA
|
||||
---help---
|
||||
This driver supports Intel(R) 10GbE PCI Express family of
|
||||
adapters. For more information on how to identify your adapter, go
|
||||
|
|
@ -2432,6 +2462,7 @@ config MYRI10GE
|
|||
select FW_LOADER
|
||||
select CRC32
|
||||
select INET_LRO
|
||||
select INTEL_IOATDMA
|
||||
---help---
|
||||
This driver supports Myricom Myri-10G Dual Protocol interface in
|
||||
Ethernet mode. If the eeprom on your board is not recent enough,
|
||||
|
|
@ -2496,6 +2527,15 @@ config BNX2X
|
|||
To compile this driver as a module, choose M here: the module
|
||||
will be called bnx2x. This is recommended.
|
||||
|
||||
config QLGE
|
||||
tristate "QLogic QLGE 10Gb Ethernet Driver Support"
|
||||
depends on PCI
|
||||
help
|
||||
This driver supports QLogic ISP8XXX 10Gb Ethernet cards.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called qlge.
|
||||
|
||||
source "drivers/net/sfc/Kconfig"
|
||||
|
||||
endif # NETDEV_10000
|
||||
|
|
|
|||
|
|
@ -15,9 +15,12 @@ obj-$(CONFIG_EHEA) += ehea/
|
|||
obj-$(CONFIG_CAN) += can/
|
||||
obj-$(CONFIG_BONDING) += bonding/
|
||||
obj-$(CONFIG_ATL1) += atlx/
|
||||
obj-$(CONFIG_ATL2) += atlx/
|
||||
obj-$(CONFIG_ATL1E) += atl1e/
|
||||
obj-$(CONFIG_GIANFAR) += gianfar_driver.o
|
||||
obj-$(CONFIG_TEHUTI) += tehuti.o
|
||||
obj-$(CONFIG_ENIC) += enic/
|
||||
obj-$(CONFIG_JME) += jme.o
|
||||
|
||||
gianfar_driver-objs := gianfar.o \
|
||||
gianfar_ethtool.o \
|
||||
|
|
@ -111,7 +114,7 @@ obj-$(CONFIG_EL2) += 3c503.o 8390p.o
|
|||
obj-$(CONFIG_NE2000) += ne.o 8390p.o
|
||||
obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o
|
||||
obj-$(CONFIG_HPLAN) += hp.o 8390p.o
|
||||
obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o
|
||||
obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390.o
|
||||
obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o
|
||||
obj-$(CONFIG_ULTRAMCA) += smc-mca.o 8390.o
|
||||
obj-$(CONFIG_ULTRA32) += smc-ultra32.o 8390.o
|
||||
|
|
@ -128,6 +131,7 @@ obj-$(CONFIG_AX88796) += ax88796.o
|
|||
obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o
|
||||
obj-$(CONFIG_MV643XX_ETH) += mv643xx_eth.o
|
||||
obj-$(CONFIG_QLA3XXX) += qla3xxx.o
|
||||
obj-$(CONFIG_QLGE) += qlge/
|
||||
|
||||
obj-$(CONFIG_PPP) += ppp_generic.o
|
||||
obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
|
||||
|
|
|
|||
|
|
@ -442,24 +442,24 @@ static int arcnet_open(struct net_device *dev)
|
|||
BUGMSG(D_NORMAL, "WARNING! Station address FF may confuse "
|
||||
"DOS networking programs!\n");
|
||||
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
if (ASTATUS() & RESETflag) {
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
ACOMMAND(CFLAGScmd | RESETclear);
|
||||
}
|
||||
|
||||
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
/* make sure we're ready to receive IRQ's. */
|
||||
AINTMASK(0);
|
||||
udelay(1); /* give it time to set the mask before
|
||||
* we reset it again. (may not even be
|
||||
* necessary)
|
||||
*/
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
lp->intmask = NORXflag | RECONflag;
|
||||
AINTMASK(lp->intmask);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
|
||||
netif_start_queue(dev);
|
||||
|
||||
|
|
@ -670,14 +670,14 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev)
|
|||
freeskb = 0;
|
||||
}
|
||||
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__FUNCTION__,ASTATUS());
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__func__,ASTATUS());
|
||||
/* make sure we didn't ignore a TX IRQ while we were in here */
|
||||
AINTMASK(0);
|
||||
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
lp->intmask |= TXFREEflag|EXCNAKflag;
|
||||
AINTMASK(lp->intmask);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__FUNCTION__,ASTATUS());
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s, status: %x\n",__FILE__,__LINE__,__func__,ASTATUS());
|
||||
|
||||
spin_unlock_irqrestore(&lp->lock, flags);
|
||||
if (freeskb) {
|
||||
|
|
@ -798,7 +798,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id)
|
|||
diagstatus = (status >> 8) & 0xFF;
|
||||
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s: status=%x\n",
|
||||
__FILE__,__LINE__,__FUNCTION__,status);
|
||||
__FILE__,__LINE__,__func__,status);
|
||||
didsomething = 0;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -238,15 +238,15 @@ static int com20020_reset(struct net_device *dev, int really_reset)
|
|||
u_char inbyte;
|
||||
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s: dev: %p, lp: %p, dev->name: %s\n",
|
||||
__FILE__,__LINE__,__FUNCTION__,dev,lp,dev->name);
|
||||
__FILE__,__LINE__,__func__,dev,lp,dev->name);
|
||||
BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n",
|
||||
dev->name, ASTATUS());
|
||||
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
lp->config = TXENcfg | (lp->timeout << 3) | (lp->backplane << 2);
|
||||
/* power-up defaults */
|
||||
SETCONF;
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
|
||||
if (really_reset) {
|
||||
/* reset the card */
|
||||
|
|
@ -254,22 +254,22 @@ static int com20020_reset(struct net_device *dev, int really_reset)
|
|||
mdelay(RESETtime * 2); /* COM20020 seems to be slower sometimes */
|
||||
}
|
||||
/* clear flags & end reset */
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
ACOMMAND(CFLAGScmd | RESETclear | CONFIGclear);
|
||||
|
||||
/* verify that the ARCnet signature byte is present */
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
|
||||
com20020_copy_from_card(dev, 0, 0, &inbyte, 1);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
if (inbyte != TESTvalue) {
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
BUGMSG(D_NORMAL, "reset failed: TESTvalue not present.\n");
|
||||
return 1;
|
||||
}
|
||||
/* enable extended (512-byte) packets */
|
||||
ACOMMAND(CONFIGcmd | EXTconf);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__FUNCTION__);
|
||||
BUGMSG(D_DEBUG, "%s: %d: %s\n",__FILE__,__LINE__,__func__);
|
||||
|
||||
/* done! return success. */
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -397,7 +397,7 @@ static int atl1e_phy_setup_autoneg_adv(struct atl1e_hw *hw)
|
|||
*/
|
||||
int atl1e_phy_commit(struct atl1e_hw *hw)
|
||||
{
|
||||
struct atl1e_adapter *adapter = (struct atl1e_adapter *)hw->adapter;
|
||||
struct atl1e_adapter *adapter = hw->adapter;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
int ret_val;
|
||||
u16 phy_data;
|
||||
|
|
@ -431,7 +431,7 @@ int atl1e_phy_commit(struct atl1e_hw *hw)
|
|||
|
||||
int atl1e_phy_init(struct atl1e_hw *hw)
|
||||
{
|
||||
struct atl1e_adapter *adapter = (struct atl1e_adapter *)hw->adapter;
|
||||
struct atl1e_adapter *adapter = hw->adapter;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
s32 ret_val;
|
||||
u16 phy_val;
|
||||
|
|
@ -525,7 +525,7 @@ int atl1e_phy_init(struct atl1e_hw *hw)
|
|||
*/
|
||||
int atl1e_reset_hw(struct atl1e_hw *hw)
|
||||
{
|
||||
struct atl1e_adapter *adapter = (struct atl1e_adapter *)hw->adapter;
|
||||
struct atl1e_adapter *adapter = hw->adapter;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
|
||||
u32 idle_status_data = 0;
|
||||
|
|
|
|||
|
|
@ -2390,9 +2390,7 @@ static int __devinit atl1e_probe(struct pci_dev *pdev,
|
|||
}
|
||||
|
||||
/* Init GPHY as early as possible due to power saving issue */
|
||||
spin_lock(&adapter->mdio_lock);
|
||||
atl1e_phy_init(&adapter->hw);
|
||||
spin_unlock(&adapter->mdio_lock);
|
||||
/* reset the controller to
|
||||
* put the device in a known good starting state */
|
||||
err = atl1e_reset_hw(&adapter->hw);
|
||||
|
|
|
|||
|
|
@ -1 +1,3 @@
|
|||
obj-$(CONFIG_ATL1) += atl1.o
|
||||
obj-$(CONFIG_ATL2) += atl2.o
|
||||
|
||||
|
|
|
|||
|
|
@ -24,16 +24,12 @@
|
|||
* file called COPYING.
|
||||
*
|
||||
* Contact Information:
|
||||
* Xiong Huang <xiong_huang@attansic.com>
|
||||
* Attansic Technology Corp. 3F 147, Xianzheng 9th Road, Zhubei,
|
||||
* Xinzhu 302, TAIWAN, REPUBLIC OF CHINA
|
||||
*
|
||||
* Xiong Huang <xiong.huang@atheros.com>
|
||||
* Jie Yang <jie.yang@atheros.com>
|
||||
* Chris Snook <csnook@redhat.com>
|
||||
* Jay Cliburn <jcliburn@gmail.com>
|
||||
*
|
||||
* This version is adapted from the Attansic reference driver for
|
||||
* inclusion in the Linux kernel. It is currently under heavy development.
|
||||
* A very incomplete list of things that need to be dealt with:
|
||||
* This version is adapted from the Attansic reference driver.
|
||||
*
|
||||
* TODO:
|
||||
* Add more ethtool functions.
|
||||
|
|
@ -2109,7 +2105,6 @@ static u16 atl1_tpd_avail(struct atl1_tpd_ring *tpd_ring)
|
|||
static int atl1_tso(struct atl1_adapter *adapter, struct sk_buff *skb,
|
||||
struct tx_packet_desc *ptpd)
|
||||
{
|
||||
/* spinlock held */
|
||||
u8 hdr_len, ip_off;
|
||||
u32 real_len;
|
||||
int err;
|
||||
|
|
@ -2196,7 +2191,6 @@ static int atl1_tx_csum(struct atl1_adapter *adapter, struct sk_buff *skb,
|
|||
static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
|
||||
struct tx_packet_desc *ptpd)
|
||||
{
|
||||
/* spinlock held */
|
||||
struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
|
||||
struct atl1_buffer *buffer_info;
|
||||
u16 buf_len = skb->len;
|
||||
|
|
@ -2303,7 +2297,6 @@ static void atl1_tx_map(struct atl1_adapter *adapter, struct sk_buff *skb,
|
|||
static void atl1_tx_queue(struct atl1_adapter *adapter, u16 count,
|
||||
struct tx_packet_desc *ptpd)
|
||||
{
|
||||
/* spinlock held */
|
||||
struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
|
||||
struct atl1_buffer *buffer_info;
|
||||
struct tx_packet_desc *tpd;
|
||||
|
|
@ -2361,7 +2354,6 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
|
|||
struct tx_packet_desc *ptpd;
|
||||
u16 frag_size;
|
||||
u16 vlan_tag;
|
||||
unsigned long flags;
|
||||
unsigned int nr_frags = 0;
|
||||
unsigned int mss = 0;
|
||||
unsigned int f;
|
||||
|
|
@ -2399,18 +2391,9 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
|
|||
}
|
||||
}
|
||||
|
||||
if (!spin_trylock_irqsave(&adapter->lock, flags)) {
|
||||
/* Can't get lock - tell upper layer to requeue */
|
||||
if (netif_msg_tx_queued(adapter))
|
||||
dev_printk(KERN_DEBUG, &adapter->pdev->dev,
|
||||
"tx locked\n");
|
||||
return NETDEV_TX_LOCKED;
|
||||
}
|
||||
|
||||
if (atl1_tpd_avail(&adapter->tpd_ring) < count) {
|
||||
/* not enough descriptors */
|
||||
netif_stop_queue(netdev);
|
||||
spin_unlock_irqrestore(&adapter->lock, flags);
|
||||
if (netif_msg_tx_queued(adapter))
|
||||
dev_printk(KERN_DEBUG, &adapter->pdev->dev,
|
||||
"tx busy\n");
|
||||
|
|
@ -2432,7 +2415,6 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
|
|||
|
||||
tso = atl1_tso(adapter, skb, ptpd);
|
||||
if (tso < 0) {
|
||||
spin_unlock_irqrestore(&adapter->lock, flags);
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
|
@ -2440,7 +2422,6 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
|
|||
if (!tso) {
|
||||
ret_val = atl1_tx_csum(adapter, skb, ptpd);
|
||||
if (ret_val < 0) {
|
||||
spin_unlock_irqrestore(&adapter->lock, flags);
|
||||
dev_kfree_skb_any(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
|
@ -2449,7 +2430,7 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
|
|||
atl1_tx_map(adapter, skb, ptpd);
|
||||
atl1_tx_queue(adapter, count, ptpd);
|
||||
atl1_update_mailbox(adapter);
|
||||
spin_unlock_irqrestore(&adapter->lock, flags);
|
||||
mmiowb();
|
||||
netdev->trans_start = jiffies;
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
|
@ -2642,6 +2623,7 @@ static void atl1_down(struct atl1_adapter *adapter)
|
|||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
|
||||
netif_stop_queue(netdev);
|
||||
del_timer_sync(&adapter->watchdog_timer);
|
||||
del_timer_sync(&adapter->phy_config_timer);
|
||||
adapter->phy_timer_pending = false;
|
||||
|
|
@ -2655,7 +2637,6 @@ static void atl1_down(struct atl1_adapter *adapter)
|
|||
adapter->link_speed = SPEED_0;
|
||||
adapter->link_duplex = -1;
|
||||
netif_carrier_off(netdev);
|
||||
netif_stop_queue(netdev);
|
||||
|
||||
atl1_clean_tx_ring(adapter);
|
||||
atl1_clean_rx_ring(adapter);
|
||||
|
|
@ -2724,6 +2705,8 @@ static int atl1_open(struct net_device *netdev)
|
|||
struct atl1_adapter *adapter = netdev_priv(netdev);
|
||||
int err;
|
||||
|
||||
netif_carrier_off(netdev);
|
||||
|
||||
/* allocate transmit descriptors */
|
||||
err = atl1_setup_ring_resources(adapter);
|
||||
if (err)
|
||||
|
|
@ -3022,7 +3005,6 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
|
|||
netdev->features = NETIF_F_HW_CSUM;
|
||||
netdev->features |= NETIF_F_SG;
|
||||
netdev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
|
||||
netdev->features |= NETIF_F_LLTX;
|
||||
|
||||
/*
|
||||
* patch for some L1 of old version,
|
||||
|
|
|
|||
3119
drivers/net/atlx/atl2.c
Normal file
3119
drivers/net/atlx/atl2.c
Normal file
File diff suppressed because it is too large
Load diff
529
drivers/net/atlx/atl2.h
Normal file
529
drivers/net/atlx/atl2.h
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
/* atl2.h -- atl2 driver definitions
|
||||
*
|
||||
* Copyright(c) 2007 Atheros Corporation. All rights reserved.
|
||||
* Copyright(c) 2006 xiong huang <xiong.huang@atheros.com>
|
||||
* Copyright(c) 2007 Chris Snook <csnook@redhat.com>
|
||||
*
|
||||
* Derived from Intel e1000 driver
|
||||
* Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59
|
||||
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _ATL2_H_
|
||||
#define _ATL2_H_
|
||||
|
||||
#include <asm/atomic.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#ifndef _ATL2_HW_H_
|
||||
#define _ATL2_HW_H_
|
||||
|
||||
#ifndef _ATL2_OSDEP_H_
|
||||
#define _ATL2_OSDEP_H_
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include "atlx.h"
|
||||
|
||||
#ifdef ETHTOOL_OPS_COMPAT
|
||||
extern int ethtool_ioctl(struct ifreq *ifr);
|
||||
#endif
|
||||
|
||||
#define PCI_COMMAND_REGISTER PCI_COMMAND
|
||||
#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
|
||||
#define ETH_ADDR_LEN ETH_ALEN
|
||||
|
||||
#define ATL2_WRITE_REG(a, reg, value) (iowrite32((value), \
|
||||
((a)->hw_addr + (reg))))
|
||||
|
||||
#define ATL2_WRITE_FLUSH(a) (ioread32((a)->hw_addr))
|
||||
|
||||
#define ATL2_READ_REG(a, reg) (ioread32((a)->hw_addr + (reg)))
|
||||
|
||||
#define ATL2_WRITE_REGB(a, reg, value) (iowrite8((value), \
|
||||
((a)->hw_addr + (reg))))
|
||||
|
||||
#define ATL2_READ_REGB(a, reg) (ioread8((a)->hw_addr + (reg)))
|
||||
|
||||
#define ATL2_WRITE_REGW(a, reg, value) (iowrite16((value), \
|
||||
((a)->hw_addr + (reg))))
|
||||
|
||||
#define ATL2_READ_REGW(a, reg) (ioread16((a)->hw_addr + (reg)))
|
||||
|
||||
#define ATL2_WRITE_REG_ARRAY(a, reg, offset, value) \
|
||||
(iowrite32((value), (((a)->hw_addr + (reg)) + ((offset) << 2))))
|
||||
|
||||
#define ATL2_READ_REG_ARRAY(a, reg, offset) \
|
||||
(ioread32(((a)->hw_addr + (reg)) + ((offset) << 2)))
|
||||
|
||||
#endif /* _ATL2_OSDEP_H_ */
|
||||
|
||||
struct atl2_adapter;
|
||||
struct atl2_hw;
|
||||
|
||||
/* function prototype */
|
||||
static s32 atl2_reset_hw(struct atl2_hw *hw);
|
||||
static s32 atl2_read_mac_addr(struct atl2_hw *hw);
|
||||
static s32 atl2_init_hw(struct atl2_hw *hw);
|
||||
static s32 atl2_get_speed_and_duplex(struct atl2_hw *hw, u16 *speed,
|
||||
u16 *duplex);
|
||||
static u32 atl2_hash_mc_addr(struct atl2_hw *hw, u8 *mc_addr);
|
||||
static void atl2_hash_set(struct atl2_hw *hw, u32 hash_value);
|
||||
static s32 atl2_read_phy_reg(struct atl2_hw *hw, u16 reg_addr, u16 *phy_data);
|
||||
static s32 atl2_write_phy_reg(struct atl2_hw *hw, u32 reg_addr, u16 phy_data);
|
||||
static void atl2_read_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value);
|
||||
static void atl2_write_pci_cfg(struct atl2_hw *hw, u32 reg, u16 *value);
|
||||
static void atl2_set_mac_addr(struct atl2_hw *hw);
|
||||
static bool atl2_read_eeprom(struct atl2_hw *hw, u32 Offset, u32 *pValue);
|
||||
static bool atl2_write_eeprom(struct atl2_hw *hw, u32 offset, u32 value);
|
||||
static s32 atl2_phy_init(struct atl2_hw *hw);
|
||||
static int atl2_check_eeprom_exist(struct atl2_hw *hw);
|
||||
static void atl2_force_ps(struct atl2_hw *hw);
|
||||
|
||||
/* register definition */
|
||||
|
||||
/* Block IDLE Status Register */
|
||||
#define IDLE_STATUS_RXMAC 1 /* 1: RXMAC is non-IDLE */
|
||||
#define IDLE_STATUS_TXMAC 2 /* 1: TXMAC is non-IDLE */
|
||||
#define IDLE_STATUS_DMAR 8 /* 1: DMAR is non-IDLE */
|
||||
#define IDLE_STATUS_DMAW 4 /* 1: DMAW is non-IDLE */
|
||||
|
||||
/* MDIO Control Register */
|
||||
#define MDIO_WAIT_TIMES 10
|
||||
|
||||
/* MAC Control Register */
|
||||
#define MAC_CTRL_DBG_TX_BKPRESURE 0x100000 /* 1: TX max backoff */
|
||||
#define MAC_CTRL_MACLP_CLK_PHY 0x8000000 /* 1: 25MHz from phy */
|
||||
#define MAC_CTRL_HALF_LEFT_BUF_SHIFT 28
|
||||
#define MAC_CTRL_HALF_LEFT_BUF_MASK 0xF /* MAC retry buf x32B */
|
||||
|
||||
/* Internal SRAM Partition Register */
|
||||
#define REG_SRAM_TXRAM_END 0x1500 /* Internal tail address of TXRAM
|
||||
* default: 2byte*1024 */
|
||||
#define REG_SRAM_RXRAM_END 0x1502 /* Internal tail address of RXRAM
|
||||
* default: 2byte*1024 */
|
||||
|
||||
/* Descriptor Control register */
|
||||
#define REG_TXD_BASE_ADDR_LO 0x1544 /* The base address of the Transmit
|
||||
* Data Mem low 32-bit(dword align) */
|
||||
#define REG_TXD_MEM_SIZE 0x1548 /* Transmit Data Memory size(by
|
||||
* double word , max 256KB) */
|
||||
#define REG_TXS_BASE_ADDR_LO 0x154C /* The base address of the Transmit
|
||||
* Status Memory low 32-bit(dword word
|
||||
* align) */
|
||||
#define REG_TXS_MEM_SIZE 0x1550 /* double word unit, max 4*2047
|
||||
* bytes. */
|
||||
#define REG_RXD_BASE_ADDR_LO 0x1554 /* The base address of the Transmit
|
||||
* Status Memory low 32-bit(unit 8
|
||||
* bytes) */
|
||||
#define REG_RXD_BUF_NUM 0x1558 /* Receive Data & Status Memory buffer
|
||||
* number (unit 1536bytes, max
|
||||
* 1536*2047) */
|
||||
|
||||
/* DMAR Control Register */
|
||||
#define REG_DMAR 0x1580
|
||||
#define DMAR_EN 0x1 /* 1: Enable DMAR */
|
||||
|
||||
/* TX Cur-Through (early tx threshold) Control Register */
|
||||
#define REG_TX_CUT_THRESH 0x1590 /* TxMac begin transmit packet
|
||||
* threshold(unit word) */
|
||||
|
||||
/* DMAW Control Register */
|
||||
#define REG_DMAW 0x15A0
|
||||
#define DMAW_EN 0x1
|
||||
|
||||
/* Flow control register */
|
||||
#define REG_PAUSE_ON_TH 0x15A8 /* RXD high watermark of overflow
|
||||
* threshold configuration register */
|
||||
#define REG_PAUSE_OFF_TH 0x15AA /* RXD lower watermark of overflow
|
||||
* threshold configuration register */
|
||||
|
||||
/* Mailbox Register */
|
||||
#define REG_MB_TXD_WR_IDX 0x15f0 /* double word align */
|
||||
#define REG_MB_RXD_RD_IDX 0x15F4 /* RXD Read index (unit: 1536byets) */
|
||||
|
||||
/* Interrupt Status Register */
|
||||
#define ISR_TIMER 1 /* Interrupt when Timer counts down to zero */
|
||||
#define ISR_MANUAL 2 /* Software manual interrupt, for debug. Set
|
||||
* when SW_MAN_INT_EN is set in Table 51
|
||||
* Selene Master Control Register
|
||||
* (Offset 0x1400). */
|
||||
#define ISR_RXF_OV 4 /* RXF overflow interrupt */
|
||||
#define ISR_TXF_UR 8 /* TXF underrun interrupt */
|
||||
#define ISR_TXS_OV 0x10 /* Internal transmit status buffer full
|
||||
* interrupt */
|
||||
#define ISR_RXS_OV 0x20 /* Internal receive status buffer full
|
||||
* interrupt */
|
||||
#define ISR_LINK_CHG 0x40 /* Link Status Change Interrupt */
|
||||
#define ISR_HOST_TXD_UR 0x80
|
||||
#define ISR_HOST_RXD_OV 0x100 /* Host rx data memory full , one pulse */
|
||||
#define ISR_DMAR_TO_RST 0x200 /* DMAR op timeout interrupt. SW should
|
||||
* do Reset */
|
||||
#define ISR_DMAW_TO_RST 0x400
|
||||
#define ISR_PHY 0x800 /* phy interrupt */
|
||||
#define ISR_TS_UPDATE 0x10000 /* interrupt after new tx pkt status written
|
||||
* to host */
|
||||
#define ISR_RS_UPDATE 0x20000 /* interrupt ater new rx pkt status written
|
||||
* to host. */
|
||||
#define ISR_TX_EARLY 0x40000 /* interrupt when txmac begin transmit one
|
||||
* packet */
|
||||
|
||||
#define ISR_TX_EVENT (ISR_TXF_UR | ISR_TXS_OV | ISR_HOST_TXD_UR |\
|
||||
ISR_TS_UPDATE | ISR_TX_EARLY)
|
||||
#define ISR_RX_EVENT (ISR_RXF_OV | ISR_RXS_OV | ISR_HOST_RXD_OV |\
|
||||
ISR_RS_UPDATE)
|
||||
|
||||
#define IMR_NORMAL_MASK (\
|
||||
/*ISR_LINK_CHG |*/\
|
||||
ISR_MANUAL |\
|
||||
ISR_DMAR_TO_RST |\
|
||||
ISR_DMAW_TO_RST |\
|
||||
ISR_PHY |\
|
||||
ISR_PHY_LINKDOWN |\
|
||||
ISR_TS_UPDATE |\
|
||||
ISR_RS_UPDATE)
|
||||
|
||||
/* Receive MAC Statistics Registers */
|
||||
#define REG_STS_RX_PAUSE 0x1700 /* Num pause packets received */
|
||||
#define REG_STS_RXD_OV 0x1704 /* Num frames dropped due to RX
|
||||
* FIFO overflow */
|
||||
#define REG_STS_RXS_OV 0x1708 /* Num frames dropped due to RX
|
||||
* Status Buffer Overflow */
|
||||
#define REG_STS_RX_FILTER 0x170C /* Num packets dropped due to
|
||||
* address filtering */
|
||||
|
||||
/* MII definitions */
|
||||
|
||||
/* PHY Common Register */
|
||||
#define MII_SMARTSPEED 0x14
|
||||
#define MII_DBG_ADDR 0x1D
|
||||
#define MII_DBG_DATA 0x1E
|
||||
|
||||
/* PCI Command Register Bit Definitions */
|
||||
#define PCI_REG_COMMAND 0x04
|
||||
#define CMD_IO_SPACE 0x0001
|
||||
#define CMD_MEMORY_SPACE 0x0002
|
||||
#define CMD_BUS_MASTER 0x0004
|
||||
|
||||
#define MEDIA_TYPE_100M_FULL 1
|
||||
#define MEDIA_TYPE_100M_HALF 2
|
||||
#define MEDIA_TYPE_10M_FULL 3
|
||||
#define MEDIA_TYPE_10M_HALF 4
|
||||
|
||||
#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x000F /* Everything */
|
||||
|
||||
/* The size (in bytes) of a ethernet packet */
|
||||
#define ENET_HEADER_SIZE 14
|
||||
#define MAXIMUM_ETHERNET_FRAME_SIZE 1518 /* with FCS */
|
||||
#define MINIMUM_ETHERNET_FRAME_SIZE 64 /* with FCS */
|
||||
#define ETHERNET_FCS_SIZE 4
|
||||
#define MAX_JUMBO_FRAME_SIZE 0x2000
|
||||
#define VLAN_SIZE 4
|
||||
|
||||
struct tx_pkt_header {
|
||||
unsigned pkt_size:11;
|
||||
unsigned:4; /* reserved */
|
||||
unsigned ins_vlan:1; /* txmac should insert vlan */
|
||||
unsigned short vlan; /* vlan tag */
|
||||
};
|
||||
/* FIXME: replace above bitfields with MASK/SHIFT defines below */
|
||||
#define TX_PKT_HEADER_SIZE_MASK 0x7FF
|
||||
#define TX_PKT_HEADER_SIZE_SHIFT 0
|
||||
#define TX_PKT_HEADER_INS_VLAN_MASK 0x1
|
||||
#define TX_PKT_HEADER_INS_VLAN_SHIFT 15
|
||||
#define TX_PKT_HEADER_VLAN_TAG_MASK 0xFFFF
|
||||
#define TX_PKT_HEADER_VLAN_TAG_SHIFT 16
|
||||
|
||||
struct tx_pkt_status {
|
||||
unsigned pkt_size:11;
|
||||
unsigned:5; /* reserved */
|
||||
unsigned ok:1; /* current packet transmitted without error */
|
||||
unsigned bcast:1; /* broadcast packet */
|
||||
unsigned mcast:1; /* multicast packet */
|
||||
unsigned pause:1; /* transmiited a pause frame */
|
||||
unsigned ctrl:1;
|
||||
unsigned defer:1; /* current packet is xmitted with defer */
|
||||
unsigned exc_defer:1;
|
||||
unsigned single_col:1;
|
||||
unsigned multi_col:1;
|
||||
unsigned late_col:1;
|
||||
unsigned abort_col:1;
|
||||
unsigned underun:1; /* current packet is aborted
|
||||
* due to txram underrun */
|
||||
unsigned:3; /* reserved */
|
||||
unsigned update:1; /* always 1'b1 in tx_status_buf */
|
||||
};
|
||||
/* FIXME: replace above bitfields with MASK/SHIFT defines below */
|
||||
#define TX_PKT_STATUS_SIZE_MASK 0x7FF
|
||||
#define TX_PKT_STATUS_SIZE_SHIFT 0
|
||||
#define TX_PKT_STATUS_OK_MASK 0x1
|
||||
#define TX_PKT_STATUS_OK_SHIFT 16
|
||||
#define TX_PKT_STATUS_BCAST_MASK 0x1
|
||||
#define TX_PKT_STATUS_BCAST_SHIFT 17
|
||||
#define TX_PKT_STATUS_MCAST_MASK 0x1
|
||||
#define TX_PKT_STATUS_MCAST_SHIFT 18
|
||||
#define TX_PKT_STATUS_PAUSE_MASK 0x1
|
||||
#define TX_PKT_STATUS_PAUSE_SHIFT 19
|
||||
#define TX_PKT_STATUS_CTRL_MASK 0x1
|
||||
#define TX_PKT_STATUS_CTRL_SHIFT 20
|
||||
#define TX_PKT_STATUS_DEFER_MASK 0x1
|
||||
#define TX_PKT_STATUS_DEFER_SHIFT 21
|
||||
#define TX_PKT_STATUS_EXC_DEFER_MASK 0x1
|
||||
#define TX_PKT_STATUS_EXC_DEFER_SHIFT 22
|
||||
#define TX_PKT_STATUS_SINGLE_COL_MASK 0x1
|
||||
#define TX_PKT_STATUS_SINGLE_COL_SHIFT 23
|
||||
#define TX_PKT_STATUS_MULTI_COL_MASK 0x1
|
||||
#define TX_PKT_STATUS_MULTI_COL_SHIFT 24
|
||||
#define TX_PKT_STATUS_LATE_COL_MASK 0x1
|
||||
#define TX_PKT_STATUS_LATE_COL_SHIFT 25
|
||||
#define TX_PKT_STATUS_ABORT_COL_MASK 0x1
|
||||
#define TX_PKT_STATUS_ABORT_COL_SHIFT 26
|
||||
#define TX_PKT_STATUS_UNDERRUN_MASK 0x1
|
||||
#define TX_PKT_STATUS_UNDERRUN_SHIFT 27
|
||||
#define TX_PKT_STATUS_UPDATE_MASK 0x1
|
||||
#define TX_PKT_STATUS_UPDATE_SHIFT 31
|
||||
|
||||
struct rx_pkt_status {
|
||||
unsigned pkt_size:11; /* packet size, max 2047 bytes */
|
||||
unsigned:5; /* reserved */
|
||||
unsigned ok:1; /* current packet received ok without error */
|
||||
unsigned bcast:1; /* current packet is broadcast */
|
||||
unsigned mcast:1; /* current packet is multicast */
|
||||
unsigned pause:1;
|
||||
unsigned ctrl:1;
|
||||
unsigned crc:1; /* received a packet with crc error */
|
||||
unsigned code:1; /* received a packet with code error */
|
||||
unsigned runt:1; /* received a packet less than 64 bytes
|
||||
* with good crc */
|
||||
unsigned frag:1; /* received a packet less than 64 bytes
|
||||
* with bad crc */
|
||||
unsigned trunc:1; /* current frame truncated due to rxram full */
|
||||
unsigned align:1; /* this packet is alignment error */
|
||||
unsigned vlan:1; /* this packet has vlan */
|
||||
unsigned:3; /* reserved */
|
||||
unsigned update:1;
|
||||
unsigned short vtag; /* vlan tag */
|
||||
unsigned:16;
|
||||
};
|
||||
/* FIXME: replace above bitfields with MASK/SHIFT defines below */
|
||||
#define RX_PKT_STATUS_SIZE_MASK 0x7FF
|
||||
#define RX_PKT_STATUS_SIZE_SHIFT 0
|
||||
#define RX_PKT_STATUS_OK_MASK 0x1
|
||||
#define RX_PKT_STATUS_OK_SHIFT 16
|
||||
#define RX_PKT_STATUS_BCAST_MASK 0x1
|
||||
#define RX_PKT_STATUS_BCAST_SHIFT 17
|
||||
#define RX_PKT_STATUS_MCAST_MASK 0x1
|
||||
#define RX_PKT_STATUS_MCAST_SHIFT 18
|
||||
#define RX_PKT_STATUS_PAUSE_MASK 0x1
|
||||
#define RX_PKT_STATUS_PAUSE_SHIFT 19
|
||||
#define RX_PKT_STATUS_CTRL_MASK 0x1
|
||||
#define RX_PKT_STATUS_CTRL_SHIFT 20
|
||||
#define RX_PKT_STATUS_CRC_MASK 0x1
|
||||
#define RX_PKT_STATUS_CRC_SHIFT 21
|
||||
#define RX_PKT_STATUS_CODE_MASK 0x1
|
||||
#define RX_PKT_STATUS_CODE_SHIFT 22
|
||||
#define RX_PKT_STATUS_RUNT_MASK 0x1
|
||||
#define RX_PKT_STATUS_RUNT_SHIFT 23
|
||||
#define RX_PKT_STATUS_FRAG_MASK 0x1
|
||||
#define RX_PKT_STATUS_FRAG_SHIFT 24
|
||||
#define RX_PKT_STATUS_TRUNK_MASK 0x1
|
||||
#define RX_PKT_STATUS_TRUNK_SHIFT 25
|
||||
#define RX_PKT_STATUS_ALIGN_MASK 0x1
|
||||
#define RX_PKT_STATUS_ALIGN_SHIFT 26
|
||||
#define RX_PKT_STATUS_VLAN_MASK 0x1
|
||||
#define RX_PKT_STATUS_VLAN_SHIFT 27
|
||||
#define RX_PKT_STATUS_UPDATE_MASK 0x1
|
||||
#define RX_PKT_STATUS_UPDATE_SHIFT 31
|
||||
#define RX_PKT_STATUS_VLAN_TAG_MASK 0xFFFF
|
||||
#define RX_PKT_STATUS_VLAN_TAG_SHIFT 32
|
||||
|
||||
struct rx_desc {
|
||||
struct rx_pkt_status status;
|
||||
unsigned char packet[1536-sizeof(struct rx_pkt_status)];
|
||||
};
|
||||
|
||||
enum atl2_speed_duplex {
|
||||
atl2_10_half = 0,
|
||||
atl2_10_full = 1,
|
||||
atl2_100_half = 2,
|
||||
atl2_100_full = 3
|
||||
};
|
||||
|
||||
struct atl2_spi_flash_dev {
|
||||
const char *manu_name; /* manufacturer id */
|
||||
/* op-code */
|
||||
u8 cmdWRSR;
|
||||
u8 cmdREAD;
|
||||
u8 cmdPROGRAM;
|
||||
u8 cmdWREN;
|
||||
u8 cmdWRDI;
|
||||
u8 cmdRDSR;
|
||||
u8 cmdRDID;
|
||||
u8 cmdSECTOR_ERASE;
|
||||
u8 cmdCHIP_ERASE;
|
||||
};
|
||||
|
||||
/* Structure containing variables used by the shared code (atl2_hw.c) */
|
||||
struct atl2_hw {
|
||||
u8 __iomem *hw_addr;
|
||||
void *back;
|
||||
|
||||
u8 preamble_len;
|
||||
u8 max_retry; /* Retransmission maximum, afterwards the
|
||||
* packet will be discarded. */
|
||||
u8 jam_ipg; /* IPG to start JAM for collision based flow
|
||||
* control in half-duplex mode. In unit of
|
||||
* 8-bit time. */
|
||||
u8 ipgt; /* Desired back to back inter-packet gap. The
|
||||
* default is 96-bit time. */
|
||||
u8 min_ifg; /* Minimum number of IFG to enforce in between
|
||||
* RX frames. Frame gap below such IFP is
|
||||
* dropped. */
|
||||
u8 ipgr1; /* 64bit Carrier-Sense window */
|
||||
u8 ipgr2; /* 96-bit IPG window */
|
||||
u8 retry_buf; /* When half-duplex mode, should hold some
|
||||
* bytes for mac retry . (8*4bytes unit) */
|
||||
|
||||
u16 fc_rxd_hi;
|
||||
u16 fc_rxd_lo;
|
||||
u16 lcol; /* Collision Window */
|
||||
u16 max_frame_size;
|
||||
|
||||
u16 MediaType;
|
||||
u16 autoneg_advertised;
|
||||
u16 pci_cmd_word;
|
||||
|
||||
u16 mii_autoneg_adv_reg;
|
||||
|
||||
u32 mem_rang;
|
||||
u32 txcw;
|
||||
u32 mc_filter_type;
|
||||
u32 num_mc_addrs;
|
||||
u32 collision_delta;
|
||||
u32 tx_packet_delta;
|
||||
u16 phy_spd_default;
|
||||
|
||||
u16 device_id;
|
||||
u16 vendor_id;
|
||||
u16 subsystem_id;
|
||||
u16 subsystem_vendor_id;
|
||||
u8 revision_id;
|
||||
|
||||
/* spi flash */
|
||||
u8 flash_vendor;
|
||||
|
||||
u8 dma_fairness;
|
||||
u8 mac_addr[NODE_ADDRESS_SIZE];
|
||||
u8 perm_mac_addr[NODE_ADDRESS_SIZE];
|
||||
|
||||
/* FIXME */
|
||||
/* bool phy_preamble_sup; */
|
||||
bool phy_configured;
|
||||
};
|
||||
|
||||
#endif /* _ATL2_HW_H_ */
|
||||
|
||||
struct atl2_ring_header {
|
||||
/* pointer to the descriptor ring memory */
|
||||
void *desc;
|
||||
/* physical adress of the descriptor ring */
|
||||
dma_addr_t dma;
|
||||
/* length of descriptor ring in bytes */
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
/* board specific private data structure */
|
||||
struct atl2_adapter {
|
||||
/* OS defined structs */
|
||||
struct net_device *netdev;
|
||||
struct pci_dev *pdev;
|
||||
struct net_device_stats net_stats;
|
||||
#ifdef NETIF_F_HW_VLAN_TX
|
||||
struct vlan_group *vlgrp;
|
||||
#endif
|
||||
u32 wol;
|
||||
u16 link_speed;
|
||||
u16 link_duplex;
|
||||
|
||||
spinlock_t stats_lock;
|
||||
|
||||
struct work_struct reset_task;
|
||||
struct work_struct link_chg_task;
|
||||
struct timer_list watchdog_timer;
|
||||
struct timer_list phy_config_timer;
|
||||
|
||||
unsigned long cfg_phy;
|
||||
bool mac_disabled;
|
||||
|
||||
/* All Descriptor memory */
|
||||
dma_addr_t ring_dma;
|
||||
void *ring_vir_addr;
|
||||
int ring_size;
|
||||
|
||||
struct tx_pkt_header *txd_ring;
|
||||
dma_addr_t txd_dma;
|
||||
|
||||
struct tx_pkt_status *txs_ring;
|
||||
dma_addr_t txs_dma;
|
||||
|
||||
struct rx_desc *rxd_ring;
|
||||
dma_addr_t rxd_dma;
|
||||
|
||||
u32 txd_ring_size; /* bytes per unit */
|
||||
u32 txs_ring_size; /* dwords per unit */
|
||||
u32 rxd_ring_size; /* 1536 bytes per unit */
|
||||
|
||||
/* read /write ptr: */
|
||||
/* host */
|
||||
u32 txd_write_ptr;
|
||||
u32 txs_next_clear;
|
||||
u32 rxd_read_ptr;
|
||||
|
||||
/* nic */
|
||||
atomic_t txd_read_ptr;
|
||||
atomic_t txs_write_ptr;
|
||||
u32 rxd_write_ptr;
|
||||
|
||||
/* Interrupt Moderator timer ( 2us resolution) */
|
||||
u16 imt;
|
||||
/* Interrupt Clear timer (2us resolution) */
|
||||
u16 ict;
|
||||
|
||||
unsigned long flags;
|
||||
/* structs defined in atl2_hw.h */
|
||||
u32 bd_number; /* board number */
|
||||
bool pci_using_64;
|
||||
bool have_msi;
|
||||
struct atl2_hw hw;
|
||||
|
||||
u32 usr_cmd;
|
||||
/* FIXME */
|
||||
/* u32 regs_buff[ATL2_REGS_LEN]; */
|
||||
u32 pci_state[16];
|
||||
|
||||
u32 *config_space;
|
||||
};
|
||||
|
||||
enum atl2_state_t {
|
||||
__ATL2_TESTING,
|
||||
__ATL2_RESETTING,
|
||||
__ATL2_DOWN
|
||||
};
|
||||
|
||||
#endif /* _ATL2_H_ */
|
||||
|
|
@ -105,7 +105,6 @@ static void atlx_check_for_link(struct atlx_adapter *adapter)
|
|||
netdev->name);
|
||||
adapter->link_speed = SPEED_0;
|
||||
netif_carrier_off(netdev);
|
||||
netif_stop_queue(netdev);
|
||||
}
|
||||
}
|
||||
schedule_work(&adapter->link_chg_task);
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ static int mii_probe (struct net_device *dev)
|
|||
|
||||
if(aup->mac_id == 0) { /* get PHY0 */
|
||||
# if defined(AU1XXX_PHY0_ADDR)
|
||||
phydev = au_macs[AU1XXX_PHY0_BUSID]->mii_bus.phy_map[AU1XXX_PHY0_ADDR];
|
||||
phydev = au_macs[AU1XXX_PHY0_BUSID]->mii_bus->phy_map[AU1XXX_PHY0_ADDR];
|
||||
# else
|
||||
printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n",
|
||||
dev->name);
|
||||
|
|
@ -298,7 +298,7 @@ static int mii_probe (struct net_device *dev)
|
|||
# endif /* defined(AU1XXX_PHY0_ADDR) */
|
||||
} else if (aup->mac_id == 1) { /* get PHY1 */
|
||||
# if defined(AU1XXX_PHY1_ADDR)
|
||||
phydev = au_macs[AU1XXX_PHY1_BUSID]->mii_bus.phy_map[AU1XXX_PHY1_ADDR];
|
||||
phydev = au_macs[AU1XXX_PHY1_BUSID]->mii_bus->phy_map[AU1XXX_PHY1_ADDR];
|
||||
# else
|
||||
printk (KERN_INFO DRV_NAME ":%s: using PHY-less setup\n",
|
||||
dev->name);
|
||||
|
|
@ -311,8 +311,8 @@ static int mii_probe (struct net_device *dev)
|
|||
|
||||
/* find the first (lowest address) PHY on the current MAC's MII bus */
|
||||
for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++)
|
||||
if (aup->mii_bus.phy_map[phy_addr]) {
|
||||
phydev = aup->mii_bus.phy_map[phy_addr];
|
||||
if (aup->mii_bus->phy_map[phy_addr]) {
|
||||
phydev = aup->mii_bus->phy_map[phy_addr];
|
||||
# if !defined(AU1XXX_PHY_SEARCH_HIGHEST_ADDR)
|
||||
break; /* break out with first one found */
|
||||
# endif
|
||||
|
|
@ -331,7 +331,7 @@ static int mii_probe (struct net_device *dev)
|
|||
* the MAC0 MII bus */
|
||||
for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
|
||||
struct phy_device *const tmp_phydev =
|
||||
au_macs[0]->mii_bus.phy_map[phy_addr];
|
||||
au_macs[0]->mii_bus->phy_map[phy_addr];
|
||||
|
||||
if (!tmp_phydev)
|
||||
continue; /* no PHY here... */
|
||||
|
|
@ -653,6 +653,8 @@ static struct net_device * au1000_probe(int port_num)
|
|||
|
||||
aup = dev->priv;
|
||||
|
||||
spin_lock_init(&aup->lock);
|
||||
|
||||
/* Allocate the data buffers */
|
||||
/* Snooping works fine with eth on all au1xxx */
|
||||
aup->vaddr = (u32)dma_alloc_noncoherent(NULL, MAX_BUF_SIZE *
|
||||
|
|
@ -696,28 +698,32 @@ static struct net_device * au1000_probe(int port_num)
|
|||
*aup->enable = 0;
|
||||
aup->mac_enabled = 0;
|
||||
|
||||
aup->mii_bus.priv = dev;
|
||||
aup->mii_bus.read = mdiobus_read;
|
||||
aup->mii_bus.write = mdiobus_write;
|
||||
aup->mii_bus.reset = mdiobus_reset;
|
||||
aup->mii_bus.name = "au1000_eth_mii";
|
||||
snprintf(aup->mii_bus.id, MII_BUS_ID_SIZE, "%x", aup->mac_id);
|
||||
aup->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
|
||||
aup->mii_bus = mdiobus_alloc();
|
||||
if (aup->mii_bus == NULL)
|
||||
goto err_out;
|
||||
|
||||
aup->mii_bus->priv = dev;
|
||||
aup->mii_bus->read = mdiobus_read;
|
||||
aup->mii_bus->write = mdiobus_write;
|
||||
aup->mii_bus->reset = mdiobus_reset;
|
||||
aup->mii_bus->name = "au1000_eth_mii";
|
||||
snprintf(aup->mii_bus->id, MII_BUS_ID_SIZE, "%x", aup->mac_id);
|
||||
aup->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
|
||||
for(i = 0; i < PHY_MAX_ADDR; ++i)
|
||||
aup->mii_bus.irq[i] = PHY_POLL;
|
||||
aup->mii_bus->irq[i] = PHY_POLL;
|
||||
|
||||
/* if known, set corresponding PHY IRQs */
|
||||
#if defined(AU1XXX_PHY_STATIC_CONFIG)
|
||||
# if defined(AU1XXX_PHY0_IRQ)
|
||||
if (AU1XXX_PHY0_BUSID == aup->mac_id)
|
||||
aup->mii_bus.irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ;
|
||||
aup->mii_bus->irq[AU1XXX_PHY0_ADDR] = AU1XXX_PHY0_IRQ;
|
||||
# endif
|
||||
# if defined(AU1XXX_PHY1_IRQ)
|
||||
if (AU1XXX_PHY1_BUSID == aup->mac_id)
|
||||
aup->mii_bus.irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ;
|
||||
aup->mii_bus->irq[AU1XXX_PHY1_ADDR] = AU1XXX_PHY1_IRQ;
|
||||
# endif
|
||||
#endif
|
||||
mdiobus_register(&aup->mii_bus);
|
||||
mdiobus_register(aup->mii_bus);
|
||||
|
||||
if (mii_probe(dev) != 0) {
|
||||
goto err_out;
|
||||
|
|
@ -753,7 +759,6 @@ static struct net_device * au1000_probe(int port_num)
|
|||
aup->tx_db_inuse[i] = pDB;
|
||||
}
|
||||
|
||||
spin_lock_init(&aup->lock);
|
||||
dev->base_addr = base;
|
||||
dev->irq = irq;
|
||||
dev->open = au1000_open;
|
||||
|
|
@ -774,6 +779,11 @@ static struct net_device * au1000_probe(int port_num)
|
|||
return dev;
|
||||
|
||||
err_out:
|
||||
if (aup->mii_bus != NULL) {
|
||||
mdiobus_unregister(aup->mii_bus);
|
||||
mdiobus_free(aup->mii_bus);
|
||||
}
|
||||
|
||||
/* here we should have a valid dev plus aup-> register addresses
|
||||
* so we can reset the mac properly.*/
|
||||
reset_mac(dev);
|
||||
|
|
@ -1004,6 +1014,8 @@ static void __exit au1000_cleanup_module(void)
|
|||
if (dev) {
|
||||
aup = (struct au1000_private *) dev->priv;
|
||||
unregister_netdev(dev);
|
||||
mdiobus_unregister(aup->mii_bus);
|
||||
mdiobus_free(aup->mii_bus);
|
||||
for (j = 0; j < NUM_RX_DMA; j++)
|
||||
if (aup->rx_db_inuse[j])
|
||||
ReleaseDB(aup, aup->rx_db_inuse[j]);
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ struct au1000_private {
|
|||
int old_duplex;
|
||||
|
||||
struct phy_device *phy_dev;
|
||||
struct mii_bus mii_bus;
|
||||
struct mii_bus *mii_bus;
|
||||
|
||||
/* These variables are just for quick access to certain regs addresses. */
|
||||
volatile mac_reg_t *mac; /* mac registers */
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ static void ax_reset_8390(struct net_device *dev)
|
|||
while ((ei_inb(addr + EN0_ISR) & ENISR_RESET) == 0) {
|
||||
if (jiffies - reset_start_time > 2*HZ/100) {
|
||||
dev_warn(&ax->dev->dev, "%s: %s did not complete.\n",
|
||||
__FUNCTION__, dev->name);
|
||||
__func__, dev->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -173,7 +173,7 @@ static void ax_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
|
|||
if (ei_status.dmaing) {
|
||||
dev_err(&ax->dev->dev, "%s: DMAing conflict in %s "
|
||||
"[DMAstat:%d][irqlock:%d].\n",
|
||||
dev->name, __FUNCTION__,
|
||||
dev->name, __func__,
|
||||
ei_status.dmaing, ei_status.irqlock);
|
||||
return;
|
||||
}
|
||||
|
|
@ -215,7 +215,7 @@ static void ax_block_input(struct net_device *dev, int count,
|
|||
dev_err(&ax->dev->dev,
|
||||
"%s: DMAing conflict in %s "
|
||||
"[DMAstat:%d][irqlock:%d].\n",
|
||||
dev->name, __FUNCTION__,
|
||||
dev->name, __func__,
|
||||
ei_status.dmaing, ei_status.irqlock);
|
||||
return;
|
||||
}
|
||||
|
|
@ -260,7 +260,7 @@ static void ax_block_output(struct net_device *dev, int count,
|
|||
if (ei_status.dmaing) {
|
||||
dev_err(&ax->dev->dev, "%s: DMAing conflict in %s."
|
||||
"[DMAstat:%d][irqlock:%d]\n",
|
||||
dev->name, __FUNCTION__,
|
||||
dev->name, __func__,
|
||||
ei_status.dmaing, ei_status.irqlock);
|
||||
return;
|
||||
}
|
||||
|
|
@ -396,7 +396,7 @@ ax_phy_issueaddr(struct net_device *dev, int phy_addr, int reg, int opc)
|
|||
{
|
||||
if (phy_debug)
|
||||
pr_debug("%s: dev %p, %04x, %04x, %d\n",
|
||||
__FUNCTION__, dev, phy_addr, reg, opc);
|
||||
__func__, dev, phy_addr, reg, opc);
|
||||
|
||||
ax_mii_ei_outbits(dev, 0x3f, 6); /* pre-amble */
|
||||
ax_mii_ei_outbits(dev, 1, 2); /* frame-start */
|
||||
|
|
@ -422,7 +422,7 @@ ax_phy_read(struct net_device *dev, int phy_addr, int reg)
|
|||
spin_unlock_irqrestore(&ei_local->page_lock, flags);
|
||||
|
||||
if (phy_debug)
|
||||
pr_debug("%s: %04x.%04x => read %04x\n", __FUNCTION__,
|
||||
pr_debug("%s: %04x.%04x => read %04x\n", __func__,
|
||||
phy_addr, reg, result);
|
||||
|
||||
return result;
|
||||
|
|
@ -436,7 +436,7 @@ ax_phy_write(struct net_device *dev, int phy_addr, int reg, int value)
|
|||
unsigned long flags;
|
||||
|
||||
dev_dbg(&ax->dev->dev, "%s: %p, %04x, %04x %04x\n",
|
||||
__FUNCTION__, dev, phy_addr, reg, value);
|
||||
__func__, dev, phy_addr, reg, value);
|
||||
|
||||
spin_lock_irqsave(&ei->page_lock, flags);
|
||||
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ static int mii_probe(struct net_device *dev)
|
|||
|
||||
/* search for connect PHY device */
|
||||
for (i = 0; i < PHY_MAX_ADDR; i++) {
|
||||
struct phy_device *const tmp_phydev = lp->mii_bus.phy_map[i];
|
||||
struct phy_device *const tmp_phydev = lp->mii_bus->phy_map[i];
|
||||
|
||||
if (!tmp_phydev)
|
||||
continue; /* no PHY here... */
|
||||
|
|
@ -811,7 +811,7 @@ static void bfin_mac_enable(void)
|
|||
{
|
||||
u32 opmode;
|
||||
|
||||
pr_debug("%s: %s\n", DRV_NAME, __FUNCTION__);
|
||||
pr_debug("%s: %s\n", DRV_NAME, __func__);
|
||||
|
||||
/* Set RX DMA */
|
||||
bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a));
|
||||
|
|
@ -847,7 +847,7 @@ static void bfin_mac_enable(void)
|
|||
/* Our watchdog timed out. Called by the networking layer */
|
||||
static void bfin_mac_timeout(struct net_device *dev)
|
||||
{
|
||||
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
|
||||
pr_debug("%s: %s\n", dev->name, __func__);
|
||||
|
||||
bfin_mac_disable();
|
||||
|
||||
|
|
@ -949,7 +949,7 @@ static int bfin_mac_open(struct net_device *dev)
|
|||
{
|
||||
struct bfin_mac_local *lp = netdev_priv(dev);
|
||||
int retval;
|
||||
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
|
||||
pr_debug("%s: %s\n", dev->name, __func__);
|
||||
|
||||
/*
|
||||
* Check that the address is valid. If its not, refuse
|
||||
|
|
@ -989,7 +989,7 @@ static int bfin_mac_open(struct net_device *dev)
|
|||
static int bfin_mac_close(struct net_device *dev)
|
||||
{
|
||||
struct bfin_mac_local *lp = netdev_priv(dev);
|
||||
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
|
||||
pr_debug("%s: %s\n", dev->name, __func__);
|
||||
|
||||
netif_stop_queue(dev);
|
||||
netif_carrier_off(dev);
|
||||
|
|
@ -1058,17 +1058,21 @@ static int __devinit bfin_mac_probe(struct platform_device *pdev)
|
|||
setup_mac_addr(ndev->dev_addr);
|
||||
|
||||
/* MDIO bus initial */
|
||||
lp->mii_bus.priv = ndev;
|
||||
lp->mii_bus.read = mdiobus_read;
|
||||
lp->mii_bus.write = mdiobus_write;
|
||||
lp->mii_bus.reset = mdiobus_reset;
|
||||
lp->mii_bus.name = "bfin_mac_mdio";
|
||||
snprintf(lp->mii_bus.id, MII_BUS_ID_SIZE, "0");
|
||||
lp->mii_bus.irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
|
||||
for (i = 0; i < PHY_MAX_ADDR; ++i)
|
||||
lp->mii_bus.irq[i] = PHY_POLL;
|
||||
lp->mii_bus = mdiobus_alloc();
|
||||
if (lp->mii_bus == NULL)
|
||||
goto out_err_mdiobus_alloc;
|
||||
|
||||
rc = mdiobus_register(&lp->mii_bus);
|
||||
lp->mii_bus->priv = ndev;
|
||||
lp->mii_bus->read = mdiobus_read;
|
||||
lp->mii_bus->write = mdiobus_write;
|
||||
lp->mii_bus->reset = mdiobus_reset;
|
||||
lp->mii_bus->name = "bfin_mac_mdio";
|
||||
snprintf(lp->mii_bus->id, MII_BUS_ID_SIZE, "0");
|
||||
lp->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
|
||||
for (i = 0; i < PHY_MAX_ADDR; ++i)
|
||||
lp->mii_bus->irq[i] = PHY_POLL;
|
||||
|
||||
rc = mdiobus_register(lp->mii_bus);
|
||||
if (rc) {
|
||||
dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
|
||||
goto out_err_mdiobus_register;
|
||||
|
|
@ -1121,8 +1125,10 @@ out_err_reg_ndev:
|
|||
free_irq(IRQ_MAC_RX, ndev);
|
||||
out_err_request_irq:
|
||||
out_err_mii_probe:
|
||||
mdiobus_unregister(&lp->mii_bus);
|
||||
mdiobus_unregister(lp->mii_bus);
|
||||
out_err_mdiobus_register:
|
||||
mdiobus_free(lp->mii_bus);
|
||||
out_err_mdiobus_alloc:
|
||||
peripheral_free_list(pin_req);
|
||||
out_err_setup_pin_mux:
|
||||
out_err_probe_mac:
|
||||
|
|
@ -1139,7 +1145,8 @@ static int __devexit bfin_mac_remove(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
mdiobus_unregister(&lp->mii_bus);
|
||||
mdiobus_unregister(lp->mii_bus);
|
||||
mdiobus_free(lp->mii_bus);
|
||||
|
||||
unregister_netdev(ndev);
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ struct bfin_mac_local {
|
|||
int old_duplex;
|
||||
|
||||
struct phy_device *phydev;
|
||||
struct mii_bus mii_bus;
|
||||
struct mii_bus *mii_bus;
|
||||
};
|
||||
|
||||
extern void bfin_get_ether_addr(char *addr);
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@
|
|||
|
||||
#define DRV_MODULE_NAME "bnx2"
|
||||
#define PFX DRV_MODULE_NAME ": "
|
||||
#define DRV_MODULE_VERSION "1.8.0"
|
||||
#define DRV_MODULE_RELDATE "Aug 14, 2008"
|
||||
#define DRV_MODULE_VERSION "1.8.1"
|
||||
#define DRV_MODULE_RELDATE "Oct 7, 2008"
|
||||
|
||||
#define RUN_AT(x) (jiffies + (x))
|
||||
|
||||
|
|
@ -69,7 +69,7 @@ static char version[] __devinitdata =
|
|||
"Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
|
||||
|
||||
MODULE_AUTHOR("Michael Chan <[email protected]>");
|
||||
MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709 Driver");
|
||||
MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/5716 Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRV_MODULE_VERSION);
|
||||
|
||||
|
|
@ -1127,7 +1127,7 @@ bnx2_init_all_rx_contexts(struct bnx2 *bp)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
bnx2_set_mac_link(struct bnx2 *bp)
|
||||
{
|
||||
u32 val;
|
||||
|
|
@ -1193,8 +1193,6 @@ bnx2_set_mac_link(struct bnx2 *bp)
|
|||
|
||||
if (CHIP_NUM(bp) == CHIP_NUM_5709)
|
||||
bnx2_init_all_rx_contexts(bp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2478,6 +2476,11 @@ bnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
|
|||
return -ENOMEM;
|
||||
mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
if (pci_dma_mapping_error(bp->pdev, mapping)) {
|
||||
__free_page(page);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rx_pg->page = page;
|
||||
pci_unmap_addr_set(rx_pg, mapping, mapping);
|
||||
rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
|
||||
|
|
@ -2520,6 +2523,10 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index)
|
|||
|
||||
mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
if (pci_dma_mapping_error(bp->pdev, mapping)) {
|
||||
dev_kfree_skb(skb);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
rx_buf->skb = skb;
|
||||
pci_unmap_addr_set(rx_buf, mapping, mapping);
|
||||
|
|
@ -2594,7 +2601,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
|
|||
sw_cons = txr->tx_cons;
|
||||
|
||||
while (sw_cons != hw_cons) {
|
||||
struct sw_bd *tx_buf;
|
||||
struct sw_tx_bd *tx_buf;
|
||||
struct sk_buff *skb;
|
||||
int i, last;
|
||||
|
||||
|
|
@ -2619,21 +2626,13 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget)
|
|||
}
|
||||
}
|
||||
|
||||
pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
|
||||
skb_headlen(skb), PCI_DMA_TODEVICE);
|
||||
skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE);
|
||||
|
||||
tx_buf->skb = NULL;
|
||||
last = skb_shinfo(skb)->nr_frags;
|
||||
|
||||
for (i = 0; i < last; i++) {
|
||||
sw_cons = NEXT_TX_BD(sw_cons);
|
||||
|
||||
pci_unmap_page(bp->pdev,
|
||||
pci_unmap_addr(
|
||||
&txr->tx_buf_ring[TX_RING_IDX(sw_cons)],
|
||||
mapping),
|
||||
skb_shinfo(skb)->frags[i].size,
|
||||
PCI_DMA_TODEVICE);
|
||||
}
|
||||
|
||||
sw_cons = NEXT_TX_BD(sw_cons);
|
||||
|
|
@ -2674,11 +2673,31 @@ bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
|
|||
{
|
||||
struct sw_pg *cons_rx_pg, *prod_rx_pg;
|
||||
struct rx_bd *cons_bd, *prod_bd;
|
||||
dma_addr_t mapping;
|
||||
int i;
|
||||
u16 hw_prod = rxr->rx_pg_prod, prod;
|
||||
u16 hw_prod, prod;
|
||||
u16 cons = rxr->rx_pg_cons;
|
||||
|
||||
cons_rx_pg = &rxr->rx_pg_ring[cons];
|
||||
|
||||
/* The caller was unable to allocate a new page to replace the
|
||||
* last one in the frags array, so we need to recycle that page
|
||||
* and then free the skb.
|
||||
*/
|
||||
if (skb) {
|
||||
struct page *page;
|
||||
struct skb_shared_info *shinfo;
|
||||
|
||||
shinfo = skb_shinfo(skb);
|
||||
shinfo->nr_frags--;
|
||||
page = shinfo->frags[shinfo->nr_frags].page;
|
||||
shinfo->frags[shinfo->nr_frags].page = NULL;
|
||||
|
||||
cons_rx_pg->page = page;
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
|
||||
hw_prod = rxr->rx_pg_prod;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
prod = RX_PG_RING_IDX(hw_prod);
|
||||
|
||||
|
|
@ -2687,20 +2706,6 @@ bnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr,
|
|||
cons_bd = &rxr->rx_pg_desc_ring[RX_RING(cons)][RX_IDX(cons)];
|
||||
prod_bd = &rxr->rx_pg_desc_ring[RX_RING(prod)][RX_IDX(prod)];
|
||||
|
||||
if (i == 0 && skb) {
|
||||
struct page *page;
|
||||
struct skb_shared_info *shinfo;
|
||||
|
||||
shinfo = skb_shinfo(skb);
|
||||
shinfo->nr_frags--;
|
||||
page = shinfo->frags[shinfo->nr_frags].page;
|
||||
shinfo->frags[shinfo->nr_frags].page = NULL;
|
||||
mapping = pci_map_page(bp->pdev, page, 0, PAGE_SIZE,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
cons_rx_pg->page = page;
|
||||
pci_unmap_addr_set(cons_rx_pg, mapping, mapping);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
if (prod != cons) {
|
||||
prod_rx_pg->page = cons_rx_pg->page;
|
||||
cons_rx_pg->page = NULL;
|
||||
|
|
@ -2786,6 +2791,8 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
|
|||
skb_put(skb, hdr_len);
|
||||
|
||||
for (i = 0; i < pages; i++) {
|
||||
dma_addr_t mapping_old;
|
||||
|
||||
frag_len = min(frag_size, (unsigned int) PAGE_SIZE);
|
||||
if (unlikely(frag_len <= 4)) {
|
||||
unsigned int tail = 4 - frag_len;
|
||||
|
|
@ -2808,9 +2815,10 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
|
|||
}
|
||||
rx_pg = &rxr->rx_pg_ring[pg_cons];
|
||||
|
||||
pci_unmap_page(bp->pdev, pci_unmap_addr(rx_pg, mapping),
|
||||
PAGE_SIZE, PCI_DMA_FROMDEVICE);
|
||||
|
||||
/* Don't unmap yet. If we're unable to allocate a new
|
||||
* page, we need to recycle the page and the DMA addr.
|
||||
*/
|
||||
mapping_old = pci_unmap_addr(rx_pg, mapping);
|
||||
if (i == pages - 1)
|
||||
frag_len -= 4;
|
||||
|
||||
|
|
@ -2827,6 +2835,9 @@ bnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, struct sk_buff *skb,
|
|||
return err;
|
||||
}
|
||||
|
||||
pci_unmap_page(bp->pdev, mapping_old,
|
||||
PAGE_SIZE, PCI_DMA_FROMDEVICE);
|
||||
|
||||
frag_size -= frag_len;
|
||||
skb->data_len += frag_len;
|
||||
skb->truesize += frag_len;
|
||||
|
|
@ -3250,6 +3261,9 @@ bnx2_set_rx_mode(struct net_device *dev)
|
|||
struct dev_addr_list *uc_ptr;
|
||||
int i;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return;
|
||||
|
||||
spin_lock_bh(&bp->phy_lock);
|
||||
|
||||
rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
|
||||
|
|
@ -4970,31 +4984,20 @@ bnx2_free_tx_skbs(struct bnx2 *bp)
|
|||
continue;
|
||||
|
||||
for (j = 0; j < TX_DESC_CNT; ) {
|
||||
struct sw_bd *tx_buf = &txr->tx_buf_ring[j];
|
||||
struct sw_tx_bd *tx_buf = &txr->tx_buf_ring[j];
|
||||
struct sk_buff *skb = tx_buf->skb;
|
||||
int k, last;
|
||||
|
||||
if (skb == NULL) {
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
|
||||
pci_unmap_single(bp->pdev,
|
||||
pci_unmap_addr(tx_buf, mapping),
|
||||
skb_headlen(skb), PCI_DMA_TODEVICE);
|
||||
skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE);
|
||||
|
||||
tx_buf->skb = NULL;
|
||||
|
||||
last = skb_shinfo(skb)->nr_frags;
|
||||
for (k = 0; k < last; k++) {
|
||||
tx_buf = &txr->tx_buf_ring[j + k + 1];
|
||||
pci_unmap_page(bp->pdev,
|
||||
pci_unmap_addr(tx_buf, mapping),
|
||||
skb_shinfo(skb)->frags[j].size,
|
||||
PCI_DMA_TODEVICE);
|
||||
}
|
||||
j += skb_shinfo(skb)->nr_frags + 1;
|
||||
dev_kfree_skb(skb);
|
||||
j += k + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5074,6 +5077,21 @@ bnx2_init_nic(struct bnx2 *bp, int reset_phy)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bnx2_shutdown_chip(struct bnx2 *bp)
|
||||
{
|
||||
u32 reset_code;
|
||||
|
||||
if (bp->flags & BNX2_FLAG_NO_WOL)
|
||||
reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
|
||||
else if (bp->wol)
|
||||
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
|
||||
else
|
||||
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
|
||||
|
||||
return bnx2_reset_chip(bp, reset_code);
|
||||
}
|
||||
|
||||
static int
|
||||
bnx2_test_registers(struct bnx2 *bp)
|
||||
{
|
||||
|
|
@ -5357,8 +5375,11 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
|
|||
for (i = 14; i < pkt_size; i++)
|
||||
packet[i] = (unsigned char) (i & 0xff);
|
||||
|
||||
map = pci_map_single(bp->pdev, skb->data, pkt_size,
|
||||
PCI_DMA_TODEVICE);
|
||||
if (skb_dma_map(&bp->pdev->dev, skb, DMA_TO_DEVICE)) {
|
||||
dev_kfree_skb(skb);
|
||||
return -EIO;
|
||||
}
|
||||
map = skb_shinfo(skb)->dma_maps[0];
|
||||
|
||||
REG_WR(bp, BNX2_HC_COMMAND,
|
||||
bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
|
||||
|
|
@ -5393,7 +5414,7 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
|
|||
|
||||
udelay(5);
|
||||
|
||||
pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
|
||||
skb_dma_unmap(&bp->pdev->dev, skb, DMA_TO_DEVICE);
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod)
|
||||
|
|
@ -5508,6 +5529,9 @@ bnx2_test_link(struct bnx2 *bp)
|
|||
{
|
||||
u32 bmsr;
|
||||
|
||||
if (!netif_running(bp->dev))
|
||||
return -ENODEV;
|
||||
|
||||
if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) {
|
||||
if (bp->link_up)
|
||||
return 0;
|
||||
|
|
@ -5600,7 +5624,7 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
|
|||
} else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
|
||||
u32 bmcr;
|
||||
|
||||
bp->current_interval = bp->timer_interval;
|
||||
bp->current_interval = BNX2_TIMER_INTERVAL;
|
||||
|
||||
bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
|
||||
|
||||
|
|
@ -5629,7 +5653,7 @@ bnx2_5706_serdes_timer(struct bnx2 *bp)
|
|||
bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT;
|
||||
}
|
||||
} else
|
||||
bp->current_interval = bp->timer_interval;
|
||||
bp->current_interval = BNX2_TIMER_INTERVAL;
|
||||
|
||||
if (check_link) {
|
||||
u32 val;
|
||||
|
|
@ -5674,11 +5698,11 @@ bnx2_5708_serdes_timer(struct bnx2 *bp)
|
|||
} else {
|
||||
bnx2_disable_forced_2g5(bp);
|
||||
bp->serdes_an_pending = 2;
|
||||
bp->current_interval = bp->timer_interval;
|
||||
bp->current_interval = BNX2_TIMER_INTERVAL;
|
||||
}
|
||||
|
||||
} else
|
||||
bp->current_interval = bp->timer_interval;
|
||||
bp->current_interval = BNX2_TIMER_INTERVAL;
|
||||
|
||||
spin_unlock(&bp->phy_lock);
|
||||
}
|
||||
|
|
@ -5951,13 +5975,14 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
struct bnx2 *bp = netdev_priv(dev);
|
||||
dma_addr_t mapping;
|
||||
struct tx_bd *txbd;
|
||||
struct sw_bd *tx_buf;
|
||||
struct sw_tx_bd *tx_buf;
|
||||
u32 len, vlan_tag_flags, last_frag, mss;
|
||||
u16 prod, ring_prod;
|
||||
int i;
|
||||
struct bnx2_napi *bnapi;
|
||||
struct bnx2_tx_ring_info *txr;
|
||||
struct netdev_queue *txq;
|
||||
struct skb_shared_info *sp;
|
||||
|
||||
/* Determine which tx ring we will be placed on */
|
||||
i = skb_get_queue_mapping(skb);
|
||||
|
|
@ -5989,7 +6014,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
}
|
||||
#endif
|
||||
if ((mss = skb_shinfo(skb)->gso_size)) {
|
||||
u32 tcp_opt_len, ip_tcp_len;
|
||||
u32 tcp_opt_len;
|
||||
struct iphdr *iph;
|
||||
|
||||
vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
|
||||
|
|
@ -6013,21 +6038,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
|
||||
}
|
||||
} else {
|
||||
if (skb_header_cloned(skb) &&
|
||||
pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
|
||||
|
||||
iph = ip_hdr(skb);
|
||||
iph->check = 0;
|
||||
iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
|
||||
tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
|
||||
iph->daddr, 0,
|
||||
IPPROTO_TCP,
|
||||
0);
|
||||
if (tcp_opt_len || (iph->ihl > 5)) {
|
||||
vlan_tag_flags |= ((iph->ihl - 5) +
|
||||
(tcp_opt_len >> 2)) << 8;
|
||||
|
|
@ -6036,11 +6047,16 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
} else
|
||||
mss = 0;
|
||||
|
||||
mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
|
||||
if (skb_dma_map(&bp->pdev->dev, skb, DMA_TO_DEVICE)) {
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
sp = skb_shinfo(skb);
|
||||
mapping = sp->dma_maps[0];
|
||||
|
||||
tx_buf = &txr->tx_buf_ring[ring_prod];
|
||||
tx_buf->skb = skb;
|
||||
pci_unmap_addr_set(tx_buf, mapping, mapping);
|
||||
|
||||
txbd = &txr->tx_desc_ring[ring_prod];
|
||||
|
||||
|
|
@ -6059,10 +6075,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
txbd = &txr->tx_desc_ring[ring_prod];
|
||||
|
||||
len = frag->size;
|
||||
mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
|
||||
len, PCI_DMA_TODEVICE);
|
||||
pci_unmap_addr_set(&txr->tx_buf_ring[ring_prod],
|
||||
mapping, mapping);
|
||||
mapping = sp->dma_maps[i + 1];
|
||||
|
||||
txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
|
||||
txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
|
||||
|
|
@ -6097,20 +6110,13 @@ static int
|
|||
bnx2_close(struct net_device *dev)
|
||||
{
|
||||
struct bnx2 *bp = netdev_priv(dev);
|
||||
u32 reset_code;
|
||||
|
||||
cancel_work_sync(&bp->reset_task);
|
||||
|
||||
bnx2_disable_int_sync(bp);
|
||||
bnx2_napi_disable(bp);
|
||||
del_timer_sync(&bp->timer);
|
||||
if (bp->flags & BNX2_FLAG_NO_WOL)
|
||||
reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
|
||||
else if (bp->wol)
|
||||
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
|
||||
else
|
||||
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
|
||||
bnx2_reset_chip(bp, reset_code);
|
||||
bnx2_shutdown_chip(bp);
|
||||
bnx2_free_irq(bp);
|
||||
bnx2_free_skbs(bp);
|
||||
bnx2_free_mem(bp);
|
||||
|
|
@ -6479,6 +6485,9 @@ bnx2_nway_reset(struct net_device *dev)
|
|||
struct bnx2 *bp = netdev_priv(dev);
|
||||
u32 bmcr;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return -EAGAIN;
|
||||
|
||||
if (!(bp->autoneg & AUTONEG_SPEED)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -6534,6 +6543,9 @@ bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
|
|||
struct bnx2 *bp = netdev_priv(dev);
|
||||
int rc;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return -EAGAIN;
|
||||
|
||||
/* parameters already validated in ethtool_get_eeprom */
|
||||
|
||||
rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
|
||||
|
|
@ -6548,6 +6560,9 @@ bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
|
|||
struct bnx2 *bp = netdev_priv(dev);
|
||||
int rc;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return -EAGAIN;
|
||||
|
||||
/* parameters already validated in ethtool_set_eeprom */
|
||||
|
||||
rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
|
||||
|
|
@ -6712,11 +6727,11 @@ bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
|
|||
bp->autoneg &= ~AUTONEG_FLOW_CTRL;
|
||||
}
|
||||
|
||||
spin_lock_bh(&bp->phy_lock);
|
||||
|
||||
bnx2_setup_phy(bp, bp->phy_port);
|
||||
|
||||
spin_unlock_bh(&bp->phy_lock);
|
||||
if (netif_running(dev)) {
|
||||
spin_lock_bh(&bp->phy_lock);
|
||||
bnx2_setup_phy(bp, bp->phy_port);
|
||||
spin_unlock_bh(&bp->phy_lock);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -6907,6 +6922,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
|
|||
{
|
||||
struct bnx2 *bp = netdev_priv(dev);
|
||||
|
||||
bnx2_set_power_state(bp, PCI_D0);
|
||||
|
||||
memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
|
||||
if (etest->flags & ETH_TEST_FL_OFFLINE) {
|
||||
int i;
|
||||
|
|
@ -6926,9 +6943,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
|
|||
if ((buf[2] = bnx2_test_loopback(bp)) != 0)
|
||||
etest->flags |= ETH_TEST_FL_FAILED;
|
||||
|
||||
if (!netif_running(bp->dev)) {
|
||||
bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
|
||||
}
|
||||
if (!netif_running(bp->dev))
|
||||
bnx2_shutdown_chip(bp);
|
||||
else {
|
||||
bnx2_init_nic(bp, 1);
|
||||
bnx2_netif_start(bp);
|
||||
|
|
@ -6956,6 +6972,8 @@ bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
|
|||
etest->flags |= ETH_TEST_FL_FAILED;
|
||||
|
||||
}
|
||||
if (!netif_running(bp->dev))
|
||||
bnx2_set_power_state(bp, PCI_D3hot);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -7021,6 +7039,8 @@ bnx2_phys_id(struct net_device *dev, u32 data)
|
|||
int i;
|
||||
u32 save;
|
||||
|
||||
bnx2_set_power_state(bp, PCI_D0);
|
||||
|
||||
if (data == 0)
|
||||
data = 2;
|
||||
|
||||
|
|
@ -7045,6 +7065,10 @@ bnx2_phys_id(struct net_device *dev, u32 data)
|
|||
}
|
||||
REG_WR(bp, BNX2_EMAC_LED, 0);
|
||||
REG_WR(bp, BNX2_MISC_CFG, save);
|
||||
|
||||
if (!netif_running(dev))
|
||||
bnx2_set_power_state(bp, PCI_D3hot);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -7516,8 +7540,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
|||
|
||||
bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS;
|
||||
|
||||
bp->timer_interval = HZ;
|
||||
bp->current_interval = HZ;
|
||||
bp->current_interval = BNX2_TIMER_INTERVAL;
|
||||
|
||||
bp->phy_addr = 1;
|
||||
|
||||
|
|
@ -7607,7 +7630,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
|
|||
bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
|
||||
|
||||
init_timer(&bp->timer);
|
||||
bp->timer.expires = RUN_AT(bp->timer_interval);
|
||||
bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL);
|
||||
bp->timer.data = (unsigned long) bp;
|
||||
bp->timer.function = bnx2_timer;
|
||||
|
||||
|
|
@ -7720,7 +7743,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
|
||||
memcpy(dev->dev_addr, bp->mac_addr, 6);
|
||||
memcpy(dev->perm_addr, bp->mac_addr, 6);
|
||||
bp->name = board_info[ent->driver_data].name;
|
||||
|
||||
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
|
||||
if (CHIP_NUM(bp) == CHIP_NUM_5709)
|
||||
|
|
@ -7747,7 +7769,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
|
||||
"IRQ %d, node addr %s\n",
|
||||
dev->name,
|
||||
bp->name,
|
||||
board_info[ent->driver_data].name,
|
||||
((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
|
||||
((CHIP_ID(bp) & 0x0ff0) >> 4),
|
||||
bnx2_bus_string(bp, str),
|
||||
|
|
@ -7781,7 +7803,6 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
{
|
||||
struct net_device *dev = pci_get_drvdata(pdev);
|
||||
struct bnx2 *bp = netdev_priv(dev);
|
||||
u32 reset_code;
|
||||
|
||||
/* PCI register 4 needs to be saved whether netif_running() or not.
|
||||
* MSI address and data need to be saved if using MSI and
|
||||
|
|
@ -7795,13 +7816,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
bnx2_netif_stop(bp);
|
||||
netif_device_detach(dev);
|
||||
del_timer_sync(&bp->timer);
|
||||
if (bp->flags & BNX2_FLAG_NO_WOL)
|
||||
reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
|
||||
else if (bp->wol)
|
||||
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
|
||||
else
|
||||
reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
|
||||
bnx2_reset_chip(bp, reset_code);
|
||||
bnx2_shutdown_chip(bp);
|
||||
bnx2_free_skbs(bp);
|
||||
bnx2_set_power_state(bp, pci_choose_state(pdev, state));
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -6526,10 +6526,14 @@ struct sw_pg {
|
|||
DECLARE_PCI_UNMAP_ADDR(mapping)
|
||||
};
|
||||
|
||||
struct sw_tx_bd {
|
||||
struct sk_buff *skb;
|
||||
};
|
||||
|
||||
#define SW_RXBD_RING_SIZE (sizeof(struct sw_bd) * RX_DESC_CNT)
|
||||
#define SW_RXPG_RING_SIZE (sizeof(struct sw_pg) * RX_DESC_CNT)
|
||||
#define RXBD_RING_SIZE (sizeof(struct rx_bd) * RX_DESC_CNT)
|
||||
#define SW_TXBD_RING_SIZE (sizeof(struct sw_bd) * TX_DESC_CNT)
|
||||
#define SW_TXBD_RING_SIZE (sizeof(struct sw_tx_bd) * TX_DESC_CNT)
|
||||
#define TXBD_RING_SIZE (sizeof(struct tx_bd) * TX_DESC_CNT)
|
||||
|
||||
/* Buffered flash (Atmel: AT45DB011B) specific information */
|
||||
|
|
@ -6597,7 +6601,7 @@ struct flash_spec {
|
|||
|
||||
struct bnx2_irq {
|
||||
irq_handler_t handler;
|
||||
u16 vector;
|
||||
unsigned int vector;
|
||||
u8 requested;
|
||||
char name[16];
|
||||
};
|
||||
|
|
@ -6609,7 +6613,7 @@ struct bnx2_tx_ring_info {
|
|||
u32 tx_bseq_addr;
|
||||
|
||||
struct tx_bd *tx_desc_ring;
|
||||
struct sw_bd *tx_buf_ring;
|
||||
struct sw_tx_bd *tx_buf_ring;
|
||||
|
||||
u16 tx_cons;
|
||||
u16 hw_tx_cons;
|
||||
|
|
@ -6654,6 +6658,8 @@ struct bnx2_napi {
|
|||
struct bnx2_tx_ring_info tx_ring;
|
||||
};
|
||||
|
||||
#define BNX2_TIMER_INTERVAL HZ
|
||||
|
||||
struct bnx2 {
|
||||
/* Fields used in the tx and intr/napi performance paths are grouped */
|
||||
/* together in the beginning of the structure. */
|
||||
|
|
@ -6701,9 +6707,6 @@ struct bnx2 {
|
|||
|
||||
/* End of fields used in the performance code paths. */
|
||||
|
||||
char *name;
|
||||
|
||||
int timer_interval;
|
||||
int current_interval;
|
||||
struct timer_list timer;
|
||||
struct work_struct reset_task;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -59,8 +59,8 @@
|
|||
#include "bnx2x.h"
|
||||
#include "bnx2x_init.h"
|
||||
|
||||
#define DRV_MODULE_VERSION "1.45.21"
|
||||
#define DRV_MODULE_RELDATE "2008/09/03"
|
||||
#define DRV_MODULE_VERSION "1.45.22"
|
||||
#define DRV_MODULE_RELDATE "2008/09/09"
|
||||
#define BNX2X_BC_VER 0x040200
|
||||
|
||||
/* Time in jiffies before concluding the transmitter is hung */
|
||||
|
|
@ -649,15 +649,16 @@ static void bnx2x_int_disable(struct bnx2x *bp)
|
|||
BNX2X_ERR("BUG! proper val not read from IGU!\n");
|
||||
}
|
||||
|
||||
static void bnx2x_int_disable_sync(struct bnx2x *bp)
|
||||
static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
|
||||
{
|
||||
int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
|
||||
int i;
|
||||
|
||||
/* disable interrupt handling */
|
||||
atomic_inc(&bp->intr_sem);
|
||||
/* prevent the HW from sending interrupts */
|
||||
bnx2x_int_disable(bp);
|
||||
if (disable_hw)
|
||||
/* prevent the HW from sending interrupts */
|
||||
bnx2x_int_disable(bp);
|
||||
|
||||
/* make sure all ISRs are done */
|
||||
if (msix) {
|
||||
|
|
@ -6086,9 +6087,9 @@ static void bnx2x_netif_start(struct bnx2x *bp)
|
|||
}
|
||||
}
|
||||
|
||||
static void bnx2x_netif_stop(struct bnx2x *bp)
|
||||
static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
|
||||
{
|
||||
bnx2x_int_disable_sync(bp);
|
||||
bnx2x_int_disable_sync(bp, disable_hw);
|
||||
if (netif_running(bp->dev)) {
|
||||
bnx2x_napi_disable(bp);
|
||||
netif_tx_disable(bp->dev);
|
||||
|
|
@ -6475,7 +6476,7 @@ load_rings_free:
|
|||
for_each_queue(bp, i)
|
||||
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
|
||||
load_int_disable:
|
||||
bnx2x_int_disable_sync(bp);
|
||||
bnx2x_int_disable_sync(bp, 1);
|
||||
/* Release IRQs */
|
||||
bnx2x_free_irq(bp);
|
||||
load_error:
|
||||
|
|
@ -6650,7 +6651,7 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
|
|||
bp->rx_mode = BNX2X_RX_MODE_NONE;
|
||||
bnx2x_set_storm_rx_mode(bp);
|
||||
|
||||
bnx2x_netif_stop(bp);
|
||||
bnx2x_netif_stop(bp, 1);
|
||||
if (!netif_running(bp->dev))
|
||||
bnx2x_napi_disable(bp);
|
||||
del_timer_sync(&bp->timer);
|
||||
|
|
@ -8791,7 +8792,7 @@ static int bnx2x_test_loopback(struct bnx2x *bp, u8 link_up)
|
|||
if (!netif_running(bp->dev))
|
||||
return BNX2X_LOOPBACK_FAILED;
|
||||
|
||||
bnx2x_netif_stop(bp);
|
||||
bnx2x_netif_stop(bp, 1);
|
||||
|
||||
if (bnx2x_run_loopback(bp, BNX2X_MAC_LOOPBACK, link_up)) {
|
||||
DP(NETIF_MSG_PROBE, "MAC loopback failed\n");
|
||||
|
|
@ -10346,6 +10347,74 @@ static int bnx2x_resume(struct pci_dev *pdev)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int bnx2x_eeh_nic_unload(struct bnx2x *bp)
|
||||
{
|
||||
int i;
|
||||
|
||||
bp->state = BNX2X_STATE_ERROR;
|
||||
|
||||
bp->rx_mode = BNX2X_RX_MODE_NONE;
|
||||
|
||||
bnx2x_netif_stop(bp, 0);
|
||||
|
||||
del_timer_sync(&bp->timer);
|
||||
bp->stats_state = STATS_STATE_DISABLED;
|
||||
DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");
|
||||
|
||||
/* Release IRQs */
|
||||
bnx2x_free_irq(bp);
|
||||
|
||||
if (CHIP_IS_E1(bp)) {
|
||||
struct mac_configuration_cmd *config =
|
||||
bnx2x_sp(bp, mcast_config);
|
||||
|
||||
for (i = 0; i < config->hdr.length_6b; i++)
|
||||
CAM_INVALIDATE(config->config_table[i]);
|
||||
}
|
||||
|
||||
/* Free SKBs, SGEs, TPA pool and driver internals */
|
||||
bnx2x_free_skbs(bp);
|
||||
for_each_queue(bp, i)
|
||||
bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE);
|
||||
bnx2x_free_mem(bp);
|
||||
|
||||
bp->state = BNX2X_STATE_CLOSED;
|
||||
|
||||
netif_carrier_off(bp->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bnx2x_eeh_recover(struct bnx2x *bp)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
mutex_init(&bp->port.phy_mutex);
|
||||
|
||||
bp->common.shmem_base = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
|
||||
bp->link_params.shmem_base = bp->common.shmem_base;
|
||||
BNX2X_DEV_INFO("shmem offset is 0x%x\n", bp->common.shmem_base);
|
||||
|
||||
if (!bp->common.shmem_base ||
|
||||
(bp->common.shmem_base < 0xA0000) ||
|
||||
(bp->common.shmem_base >= 0xC0000)) {
|
||||
BNX2X_DEV_INFO("MCP not active\n");
|
||||
bp->flags |= NO_MCP_FLAG;
|
||||
return;
|
||||
}
|
||||
|
||||
val = SHMEM_RD(bp, validity_map[BP_PORT(bp)]);
|
||||
if ((val & (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
|
||||
!= (SHR_MEM_VALIDITY_DEV_INFO | SHR_MEM_VALIDITY_MB))
|
||||
BNX2X_ERR("BAD MCP validity signature\n");
|
||||
|
||||
if (!BP_NOMCP(bp)) {
|
||||
bp->fw_seq = (SHMEM_RD(bp, func_mb[BP_FUNC(bp)].drv_mb_header)
|
||||
& DRV_MSG_SEQ_NUMBER_MASK);
|
||||
BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* bnx2x_io_error_detected - called when PCI error is detected
|
||||
* @pdev: Pointer to PCI device
|
||||
|
|
@ -10365,7 +10434,7 @@ static pci_ers_result_t bnx2x_io_error_detected(struct pci_dev *pdev,
|
|||
netif_device_detach(dev);
|
||||
|
||||
if (netif_running(dev))
|
||||
bnx2x_nic_unload(bp, UNLOAD_CLOSE);
|
||||
bnx2x_eeh_nic_unload(bp);
|
||||
|
||||
pci_disable_device(pdev);
|
||||
|
||||
|
|
@ -10420,8 +10489,10 @@ static void bnx2x_io_resume(struct pci_dev *pdev)
|
|||
|
||||
rtnl_lock();
|
||||
|
||||
bnx2x_eeh_recover(bp);
|
||||
|
||||
if (netif_running(dev))
|
||||
bnx2x_nic_load(bp, LOAD_OPEN);
|
||||
bnx2x_nic_load(bp, LOAD_NORMAL);
|
||||
|
||||
netif_device_attach(dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include <linux/in.h>
|
||||
#include <net/ipx.h>
|
||||
#include <net/arp.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include "bonding.h"
|
||||
#include "bond_alb.h"
|
||||
|
|
@ -81,6 +82,7 @@
|
|||
#define RLB_PROMISC_TIMEOUT 10*ALB_TIMER_TICKS_PER_SEC
|
||||
|
||||
static const u8 mac_bcast[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
|
||||
static const u8 mac_v6_allmcast[ETH_ALEN] = {0x33,0x33,0x00,0x00,0x00,0x01};
|
||||
static const int alb_delta_in_ticks = HZ / ALB_TIMER_TICKS_PER_SEC;
|
||||
|
||||
#pragma pack(1)
|
||||
|
|
@ -710,7 +712,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
|
|||
struct arp_pkt *arp = arp_pkt(skb);
|
||||
struct slave *tx_slave = NULL;
|
||||
|
||||
if (arp->op_code == __constant_htons(ARPOP_REPLY)) {
|
||||
if (arp->op_code == htons(ARPOP_REPLY)) {
|
||||
/* the arp must be sent on the selected
|
||||
* rx channel
|
||||
*/
|
||||
|
|
@ -719,7 +721,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)
|
|||
memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN);
|
||||
}
|
||||
dprintk("Server sent ARP Reply packet\n");
|
||||
} else if (arp->op_code == __constant_htons(ARPOP_REQUEST)) {
|
||||
} else if (arp->op_code == htons(ARPOP_REQUEST)) {
|
||||
/* Create an entry in the rx_hashtbl for this client as a
|
||||
* place holder.
|
||||
* When the arp reply is received the entry will be updated
|
||||
|
|
@ -1290,6 +1292,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
|
|||
u32 hash_index = 0;
|
||||
const u8 *hash_start = NULL;
|
||||
int res = 1;
|
||||
struct ipv6hdr *ip6hdr;
|
||||
|
||||
skb_reset_mac_header(skb);
|
||||
eth_data = eth_hdr(skb);
|
||||
|
|
@ -1319,11 +1322,32 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
|
|||
}
|
||||
break;
|
||||
case ETH_P_IPV6:
|
||||
/* IPv6 doesn't really use broadcast mac address, but leave
|
||||
* that here just in case.
|
||||
*/
|
||||
if (memcmp(eth_data->h_dest, mac_bcast, ETH_ALEN) == 0) {
|
||||
do_tx_balance = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* IPv6 uses all-nodes multicast as an equivalent to
|
||||
* broadcasts in IPv4.
|
||||
*/
|
||||
if (memcmp(eth_data->h_dest, mac_v6_allmcast, ETH_ALEN) == 0) {
|
||||
do_tx_balance = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Additianally, DAD probes should not be tx-balanced as that
|
||||
* will lead to false positives for duplicate addresses and
|
||||
* prevent address configuration from working.
|
||||
*/
|
||||
ip6hdr = ipv6_hdr(skb);
|
||||
if (ipv6_addr_any(&ip6hdr->saddr)) {
|
||||
do_tx_balance = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
hash_start = (char *)&(ipv6_hdr(skb)->daddr);
|
||||
hash_size = sizeof(ipv6_hdr(skb)->daddr);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -3702,7 +3702,7 @@ static int bond_xmit_hash_policy_l23(struct sk_buff *skb,
|
|||
struct ethhdr *data = (struct ethhdr *)skb->data;
|
||||
struct iphdr *iph = ip_hdr(skb);
|
||||
|
||||
if (skb->protocol == __constant_htons(ETH_P_IP)) {
|
||||
if (skb->protocol == htons(ETH_P_IP)) {
|
||||
return ((ntohl(iph->saddr ^ iph->daddr) & 0xffff) ^
|
||||
(data->h_dest[5] ^ bond_dev->dev_addr[5])) % count;
|
||||
}
|
||||
|
|
@ -3723,8 +3723,8 @@ static int bond_xmit_hash_policy_l34(struct sk_buff *skb,
|
|||
__be16 *layer4hdr = (__be16 *)((u32 *)iph + iph->ihl);
|
||||
int layer4_xor = 0;
|
||||
|
||||
if (skb->protocol == __constant_htons(ETH_P_IP)) {
|
||||
if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) &&
|
||||
if (skb->protocol == htons(ETH_P_IP)) {
|
||||
if (!(iph->frag_off & htons(IP_MF|IP_OFFSET)) &&
|
||||
(iph->protocol == IPPROTO_TCP ||
|
||||
iph->protocol == IPPROTO_UDP)) {
|
||||
layer4_xor = ntohs((*layer4hdr ^ *(layer4hdr + 1)));
|
||||
|
|
@ -4493,6 +4493,12 @@ static void bond_ethtool_get_drvinfo(struct net_device *bond_dev,
|
|||
|
||||
static const struct ethtool_ops bond_ethtool_ops = {
|
||||
.get_drvinfo = bond_ethtool_get_drvinfo,
|
||||
.get_link = ethtool_op_get_link,
|
||||
.get_tx_csum = ethtool_op_get_tx_csum,
|
||||
.get_sg = ethtool_op_get_sg,
|
||||
.get_tso = ethtool_op_get_tso,
|
||||
.get_ufo = ethtool_op_get_ufo,
|
||||
.get_flags = ethtool_op_get_flags,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
#ifdef BONDING_DEBUG
|
||||
#define dprintk(fmt, args...) \
|
||||
printk(KERN_DEBUG \
|
||||
DRV_NAME ": %s() %d: " fmt, __FUNCTION__, __LINE__ , ## args )
|
||||
DRV_NAME ": %s() %d: " fmt, __func__, __LINE__ , ## args )
|
||||
#else
|
||||
#define dprintk(fmt, args...)
|
||||
#endif /* BONDING_DEBUG */
|
||||
|
|
@ -333,5 +333,13 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
|
|||
void bond_register_arp(struct bonding *);
|
||||
void bond_unregister_arp(struct bonding *);
|
||||
|
||||
/* exported from bond_main.c */
|
||||
extern struct list_head bond_dev_list;
|
||||
extern struct bond_parm_tbl bond_lacp_tbl[];
|
||||
extern struct bond_parm_tbl bond_mode_tbl[];
|
||||
extern struct bond_parm_tbl xmit_hashtype_tbl[];
|
||||
extern struct bond_parm_tbl arp_validate_tbl[];
|
||||
extern struct bond_parm_tbl fail_over_mac_tbl[];
|
||||
|
||||
#endif /* _LINUX_BONDING_H */
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/mm.h>
|
||||
|
|
@ -91,6 +92,7 @@
|
|||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#include <net/checksum.h>
|
||||
|
||||
|
|
@ -197,6 +199,7 @@ static int link_mode;
|
|||
MODULE_AUTHOR("Adrian Sun ([email protected])");
|
||||
MODULE_DESCRIPTION("Sun Cassini(+) ethernet driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_FIRMWARE("sun/cassini.bin");
|
||||
module_param(cassini_debug, int, 0);
|
||||
MODULE_PARM_DESC(cassini_debug, "Cassini bitmapped debugging message enable value");
|
||||
module_param(link_mode, int, 0);
|
||||
|
|
@ -812,9 +815,44 @@ static int cas_reset_mii_phy(struct cas *cp)
|
|||
return (limit <= 0);
|
||||
}
|
||||
|
||||
static int cas_saturn_firmware_init(struct cas *cp)
|
||||
{
|
||||
const struct firmware *fw;
|
||||
const char fw_name[] = "sun/cassini.bin";
|
||||
int err;
|
||||
|
||||
if (PHY_NS_DP83065 != cp->phy_id)
|
||||
return 0;
|
||||
|
||||
err = request_firmware(&fw, fw_name, &cp->pdev->dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "cassini: Failed to load firmware \"%s\"\n",
|
||||
fw_name);
|
||||
return err;
|
||||
}
|
||||
if (fw->size < 2) {
|
||||
printk(KERN_ERR "cassini: bogus length %zu in \"%s\"\n",
|
||||
fw->size, fw_name);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
cp->fw_load_addr= fw->data[1] << 8 | fw->data[0];
|
||||
cp->fw_size = fw->size - 2;
|
||||
cp->fw_data = vmalloc(cp->fw_size);
|
||||
if (!cp->fw_data) {
|
||||
err = -ENOMEM;
|
||||
printk(KERN_ERR "cassini: \"%s\" Failed %d\n", fw_name, err);
|
||||
goto out;
|
||||
}
|
||||
memcpy(cp->fw_data, &fw->data[2], cp->fw_size);
|
||||
out:
|
||||
release_firmware(fw);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void cas_saturn_firmware_load(struct cas *cp)
|
||||
{
|
||||
cas_saturn_patch_t *patch = cas_saturn_patch;
|
||||
int i;
|
||||
|
||||
cas_phy_powerdown(cp);
|
||||
|
||||
|
|
@ -833,11 +871,9 @@ static void cas_saturn_firmware_load(struct cas *cp)
|
|||
|
||||
/* download new firmware */
|
||||
cas_phy_write(cp, DP83065_MII_MEM, 0x1);
|
||||
cas_phy_write(cp, DP83065_MII_REGE, patch->addr);
|
||||
while (patch->addr) {
|
||||
cas_phy_write(cp, DP83065_MII_REGD, patch->val);
|
||||
patch++;
|
||||
}
|
||||
cas_phy_write(cp, DP83065_MII_REGE, cp->fw_load_addr);
|
||||
for (i = 0; i < cp->fw_size; i++)
|
||||
cas_phy_write(cp, DP83065_MII_REGD, cp->fw_data[i]);
|
||||
|
||||
/* enable firmware */
|
||||
cas_phy_write(cp, DP83065_MII_REGE, 0x8ff8);
|
||||
|
|
@ -2182,7 +2218,7 @@ static inline void cas_rx_flow_pkt(struct cas *cp, const u64 *words,
|
|||
* do any additional locking here. stick the buffer
|
||||
* at the end.
|
||||
*/
|
||||
__skb_insert(skb, flow->prev, (struct sk_buff *) flow, flow);
|
||||
__skb_queue_tail(flow, skb);
|
||||
if (words[0] & RX_COMP1_RELEASE_FLOW) {
|
||||
while ((skb = __skb_dequeue(flow))) {
|
||||
cas_skb_release(skb);
|
||||
|
|
@ -5108,6 +5144,9 @@ static int __devinit cas_init_one(struct pci_dev *pdev,
|
|||
cas_reset(cp, 0);
|
||||
if (cas_check_invariants(cp))
|
||||
goto err_out_iounmap;
|
||||
if (cp->cas_flags & CAS_FLAG_SATURN)
|
||||
if (cas_saturn_firmware_init(cp))
|
||||
goto err_out_iounmap;
|
||||
|
||||
cp->init_block = (struct cas_init_block *)
|
||||
pci_alloc_consistent(pdev, sizeof(struct cas_init_block),
|
||||
|
|
@ -5217,6 +5256,9 @@ static void __devexit cas_remove_one(struct pci_dev *pdev)
|
|||
cp = netdev_priv(dev);
|
||||
unregister_netdev(dev);
|
||||
|
||||
if (cp->fw_data)
|
||||
vfree(cp->fw_data);
|
||||
|
||||
mutex_lock(&cp->pm_mutex);
|
||||
flush_scheduled_work();
|
||||
if (cp->hw_running)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -302,13 +302,7 @@ static int cpmac_mdio_reset(struct mii_bus *bus)
|
|||
|
||||
static int mii_irqs[PHY_MAX_ADDR] = { PHY_POLL, };
|
||||
|
||||
static struct mii_bus cpmac_mii = {
|
||||
.name = "cpmac-mii",
|
||||
.read = cpmac_mdio_read,
|
||||
.write = cpmac_mdio_write,
|
||||
.reset = cpmac_mdio_reset,
|
||||
.irq = mii_irqs,
|
||||
};
|
||||
static struct mii_bus *cpmac_mii;
|
||||
|
||||
static int cpmac_config(struct net_device *dev, struct ifmap *map)
|
||||
{
|
||||
|
|
@ -1116,7 +1110,7 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
|
|||
for (phy_id = 0; phy_id < PHY_MAX_ADDR; phy_id++) {
|
||||
if (!(pdata->phy_mask & (1 << phy_id)))
|
||||
continue;
|
||||
if (!cpmac_mii.phy_map[phy_id])
|
||||
if (!cpmac_mii->phy_map[phy_id])
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1168,7 +1162,7 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
|
|||
priv->msg_enable = netif_msg_init(debug_level, 0xff);
|
||||
memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr));
|
||||
|
||||
priv->phy = phy_connect(dev, cpmac_mii.phy_map[phy_id]->dev.bus_id,
|
||||
priv->phy = phy_connect(dev, cpmac_mii->phy_map[phy_id]->dev.bus_id,
|
||||
&cpmac_adjust_link, 0, PHY_INTERFACE_MODE_MII);
|
||||
if (IS_ERR(priv->phy)) {
|
||||
if (netif_msg_drv(priv))
|
||||
|
|
@ -1216,11 +1210,22 @@ int __devinit cpmac_init(void)
|
|||
u32 mask;
|
||||
int i, res;
|
||||
|
||||
cpmac_mii.priv = ioremap(AR7_REGS_MDIO, 256);
|
||||
cpmac_mii = mdiobus_alloc();
|
||||
if (cpmac_mii == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!cpmac_mii.priv) {
|
||||
cpmac_mii->name = "cpmac-mii";
|
||||
cpmac_mii->read = cpmac_mdio_read;
|
||||
cpmac_mii->write = cpmac_mdio_write;
|
||||
cpmac_mii->reset = cpmac_mdio_reset;
|
||||
cpmac_mii->irq = mii_irqs;
|
||||
|
||||
cpmac_mii->priv = ioremap(AR7_REGS_MDIO, 256);
|
||||
|
||||
if (!cpmac_mii->priv) {
|
||||
printk(KERN_ERR "Can't ioremap mdio registers\n");
|
||||
return -ENXIO;
|
||||
res = -ENXIO;
|
||||
goto fail_alloc;
|
||||
}
|
||||
|
||||
#warning FIXME: unhardcode gpio&reset bits
|
||||
|
|
@ -1230,10 +1235,10 @@ int __devinit cpmac_init(void)
|
|||
ar7_device_reset(AR7_RESET_BIT_CPMAC_HI);
|
||||
ar7_device_reset(AR7_RESET_BIT_EPHY);
|
||||
|
||||
cpmac_mii.reset(&cpmac_mii);
|
||||
cpmac_mii->reset(cpmac_mii);
|
||||
|
||||
for (i = 0; i < 300000; i++)
|
||||
if ((mask = cpmac_read(cpmac_mii.priv, CPMAC_MDIO_ALIVE)))
|
||||
if ((mask = cpmac_read(cpmac_mii->priv, CPMAC_MDIO_ALIVE)))
|
||||
break;
|
||||
else
|
||||
cpu_relax();
|
||||
|
|
@ -1244,10 +1249,10 @@ int __devinit cpmac_init(void)
|
|||
mask = 0;
|
||||
}
|
||||
|
||||
cpmac_mii.phy_mask = ~(mask | 0x80000000);
|
||||
snprintf(cpmac_mii.id, MII_BUS_ID_SIZE, "0");
|
||||
cpmac_mii->phy_mask = ~(mask | 0x80000000);
|
||||
snprintf(cpmac_mii->id, MII_BUS_ID_SIZE, "0");
|
||||
|
||||
res = mdiobus_register(&cpmac_mii);
|
||||
res = mdiobus_register(cpmac_mii);
|
||||
if (res)
|
||||
goto fail_mii;
|
||||
|
||||
|
|
@ -1258,10 +1263,13 @@ int __devinit cpmac_init(void)
|
|||
return 0;
|
||||
|
||||
fail_cpmac:
|
||||
mdiobus_unregister(&cpmac_mii);
|
||||
mdiobus_unregister(cpmac_mii);
|
||||
|
||||
fail_mii:
|
||||
iounmap(cpmac_mii.priv);
|
||||
iounmap(cpmac_mii->priv);
|
||||
|
||||
fail_alloc:
|
||||
mdiobus_free(cpmac_mii);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
@ -1269,8 +1277,9 @@ fail_mii:
|
|||
void __devexit cpmac_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&cpmac_driver);
|
||||
mdiobus_unregister(&cpmac_mii);
|
||||
iounmap(cpmac_mii.priv);
|
||||
mdiobus_unregister(cpmac_mii);
|
||||
mdiobus_free(cpmac_mii);
|
||||
iounmap(cpmac_mii->priv);
|
||||
}
|
||||
|
||||
module_init(cpmac_init);
|
||||
|
|
|
|||
|
|
@ -194,6 +194,12 @@ static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
|
|||
#define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */
|
||||
static unsigned int netcard_portlist[] __used __initdata = {CIRRUS_DEFAULT_BASE, 0};
|
||||
static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
|
||||
#elif defined(CONFIG_MACH_MX31ADS)
|
||||
#include <mach/board-mx31ads.h>
|
||||
static unsigned int netcard_portlist[] __used __initdata = {
|
||||
PBC_BASE_ADDRESS + PBC_CS8900A_IOBASE + 0x300, 0
|
||||
};
|
||||
static unsigned cs8900_irq_map[] = {EXPIO_INT_ENET_INT, 0, 0, 0};
|
||||
#else
|
||||
static unsigned int netcard_portlist[] __used __initdata =
|
||||
{ 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
|
||||
|
|
@ -802,7 +808,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
|
|||
} else {
|
||||
i = lp->isa_config & INT_NO_MASK;
|
||||
if (lp->chip_type == CS8900) {
|
||||
#if defined(CONFIG_MACH_IXDP2351) || defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX010X)
|
||||
#ifdef CONFIG_CS89x0_NONISA_IRQ
|
||||
i = cs8900_irq_map[0];
|
||||
#else
|
||||
/* Translate the IRQ using the IRQ mapping table. */
|
||||
|
|
@ -1029,6 +1035,7 @@ skip_this_frame:
|
|||
|
||||
void __init reset_chip(struct net_device *dev)
|
||||
{
|
||||
#if !defined(CONFIG_MACH_MX31ADS)
|
||||
#if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01)
|
||||
struct net_local *lp = netdev_priv(dev);
|
||||
int ioaddr = dev->base_addr;
|
||||
|
|
@ -1057,6 +1064,7 @@ void __init reset_chip(struct net_device *dev)
|
|||
reset_start_time = jiffies;
|
||||
while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2)
|
||||
;
|
||||
#endif /* !CONFIG_MACH_MX31ADS */
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1304,7 +1312,7 @@ net_open(struct net_device *dev)
|
|||
else
|
||||
#endif
|
||||
{
|
||||
#if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX010X)
|
||||
#ifndef CONFIG_CS89x0_NONISA_IRQ
|
||||
if (((1 << dev->irq) & lp->irq_map) == 0) {
|
||||
printk(KERN_ERR "%s: IRQ %d is not in our map of allowable IRQs, which is %x\n",
|
||||
dev->name, dev->irq, lp->irq_map);
|
||||
|
|
@ -1397,9 +1405,7 @@ net_open(struct net_device *dev)
|
|||
release_dma:
|
||||
#if ALLOW_DMA
|
||||
free_dma(dev->dma);
|
||||
#endif
|
||||
release_irq:
|
||||
#if ALLOW_DMA
|
||||
release_dma_buff(lp);
|
||||
#endif
|
||||
writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON));
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ struct port_info {
|
|||
struct adapter *adapter;
|
||||
struct vlan_group *vlan_grp;
|
||||
struct sge_qset *qs;
|
||||
const struct port_type_info *port_type;
|
||||
u8 port_id;
|
||||
u8 rx_csum_offload;
|
||||
u8 nqsets;
|
||||
|
|
@ -124,8 +123,7 @@ struct sge_rspq { /* state for an SGE response queue */
|
|||
dma_addr_t phys_addr; /* physical address of the ring */
|
||||
unsigned int cntxt_id; /* SGE context id for the response q */
|
||||
spinlock_t lock; /* guards response processing */
|
||||
struct sk_buff *rx_head; /* offload packet receive queue head */
|
||||
struct sk_buff *rx_tail; /* offload packet receive queue tail */
|
||||
struct sk_buff_head rx_queue; /* offload packet receive queue */
|
||||
struct sk_buff *pg_skb; /* used to build frag list in napi handler */
|
||||
|
||||
unsigned long offload_pkts;
|
||||
|
|
@ -241,6 +239,7 @@ struct adapter {
|
|||
unsigned int check_task_cnt;
|
||||
struct delayed_work adap_check_task;
|
||||
struct work_struct ext_intr_handler_task;
|
||||
struct work_struct fatal_error_handler_task;
|
||||
|
||||
struct dentry *debugfs_root;
|
||||
|
||||
|
|
@ -282,9 +281,11 @@ int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb);
|
|||
void t3_os_ext_intr_handler(struct adapter *adapter);
|
||||
void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status,
|
||||
int speed, int duplex, int fc);
|
||||
void t3_os_phymod_changed(struct adapter *adap, int port_id);
|
||||
|
||||
void t3_sge_start(struct adapter *adap);
|
||||
void t3_sge_stop(struct adapter *adap);
|
||||
void t3_stop_sge_timers(struct adapter *adap);
|
||||
void t3_free_sge_resources(struct adapter *adap);
|
||||
void t3_sge_err_intr_handler(struct adapter *adapter);
|
||||
irq_handler_t t3_intr_handler(struct adapter *adap, int polling);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -193,22 +193,13 @@ struct mdio_ops {
|
|||
struct adapter_info {
|
||||
unsigned char nports; /* # of ports */
|
||||
unsigned char phy_base_addr; /* MDIO PHY base address */
|
||||
unsigned char mdien;
|
||||
unsigned char mdiinv;
|
||||
unsigned int gpio_out; /* GPIO output settings */
|
||||
unsigned int gpio_intr; /* GPIO IRQ enable mask */
|
||||
unsigned char gpio_intr[MAX_NPORTS]; /* GPIO PHY IRQ pins */
|
||||
unsigned long caps; /* adapter capabilities */
|
||||
const struct mdio_ops *mdio_ops; /* MDIO operations */
|
||||
const char *desc; /* product description */
|
||||
};
|
||||
|
||||
struct port_type_info {
|
||||
void (*phy_prep)(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *ops);
|
||||
unsigned int caps;
|
||||
const char *desc;
|
||||
};
|
||||
|
||||
struct mc5_stats {
|
||||
unsigned long parity_err;
|
||||
unsigned long active_rgn_full;
|
||||
|
|
@ -358,6 +349,7 @@ struct qset_params { /* SGE queue set parameters */
|
|||
unsigned int jumbo_size; /* # of entries in jumbo free list */
|
||||
unsigned int txq_size[SGE_TXQ_PER_SET]; /* Tx queue sizes */
|
||||
unsigned int cong_thres; /* FL congestion threshold */
|
||||
unsigned int vector; /* Interrupt (line or vector) number */
|
||||
};
|
||||
|
||||
struct sge_params {
|
||||
|
|
@ -525,12 +517,25 @@ enum {
|
|||
MAC_RXFIFO_SIZE = 32768
|
||||
};
|
||||
|
||||
/* IEEE 802.3ae specified MDIO devices */
|
||||
/* IEEE 802.3 specified MDIO devices */
|
||||
enum {
|
||||
MDIO_DEV_PMA_PMD = 1,
|
||||
MDIO_DEV_WIS = 2,
|
||||
MDIO_DEV_PCS = 3,
|
||||
MDIO_DEV_XGXS = 4
|
||||
MDIO_DEV_XGXS = 4,
|
||||
MDIO_DEV_ANEG = 7,
|
||||
MDIO_DEV_VEND1 = 30,
|
||||
MDIO_DEV_VEND2 = 31
|
||||
};
|
||||
|
||||
/* LASI control and status registers */
|
||||
enum {
|
||||
RX_ALARM_CTRL = 0x9000,
|
||||
TX_ALARM_CTRL = 0x9001,
|
||||
LASI_CTRL = 0x9002,
|
||||
RX_ALARM_STAT = 0x9003,
|
||||
TX_ALARM_STAT = 0x9004,
|
||||
LASI_STAT = 0x9005
|
||||
};
|
||||
|
||||
/* PHY loopback direction */
|
||||
|
|
@ -542,12 +547,23 @@ enum {
|
|||
/* PHY interrupt types */
|
||||
enum {
|
||||
cphy_cause_link_change = 1,
|
||||
cphy_cause_fifo_error = 2
|
||||
cphy_cause_fifo_error = 2,
|
||||
cphy_cause_module_change = 4,
|
||||
};
|
||||
|
||||
/* PHY module types */
|
||||
enum {
|
||||
phy_modtype_none,
|
||||
phy_modtype_sr,
|
||||
phy_modtype_lr,
|
||||
phy_modtype_lrm,
|
||||
phy_modtype_twinax,
|
||||
phy_modtype_twinax_long,
|
||||
phy_modtype_unknown
|
||||
};
|
||||
|
||||
/* PHY operations */
|
||||
struct cphy_ops {
|
||||
void (*destroy)(struct cphy *phy);
|
||||
int (*reset)(struct cphy *phy, int wait);
|
||||
|
||||
int (*intr_enable)(struct cphy *phy);
|
||||
|
|
@ -568,8 +584,12 @@ struct cphy_ops {
|
|||
|
||||
/* A PHY instance */
|
||||
struct cphy {
|
||||
int addr; /* PHY address */
|
||||
u8 addr; /* PHY address */
|
||||
u8 modtype; /* PHY module type */
|
||||
short priv; /* scratch pad */
|
||||
unsigned int caps; /* PHY capabilities */
|
||||
struct adapter *adapter; /* associated adapter */
|
||||
const char *desc; /* PHY description */
|
||||
unsigned long fifo_errors; /* FIFO over/under-flows */
|
||||
const struct cphy_ops *ops; /* PHY operations */
|
||||
int (*mdio_read)(struct adapter *adapter, int phy_addr, int mmd_addr,
|
||||
|
|
@ -594,10 +614,13 @@ static inline int mdio_write(struct cphy *phy, int mmd, int reg,
|
|||
/* Convenience initializer */
|
||||
static inline void cphy_init(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, struct cphy_ops *phy_ops,
|
||||
const struct mdio_ops *mdio_ops)
|
||||
const struct mdio_ops *mdio_ops,
|
||||
unsigned int caps, const char *desc)
|
||||
{
|
||||
phy->adapter = adapter;
|
||||
phy->addr = phy_addr;
|
||||
phy->caps = caps;
|
||||
phy->adapter = adapter;
|
||||
phy->desc = desc;
|
||||
phy->ops = phy_ops;
|
||||
if (mdio_ops) {
|
||||
phy->mdio_read = mdio_ops->read;
|
||||
|
|
@ -668,7 +691,12 @@ int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
|
|||
unsigned int set);
|
||||
int t3_phy_reset(struct cphy *phy, int mmd, int wait);
|
||||
int t3_phy_advertise(struct cphy *phy, unsigned int advert);
|
||||
int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert);
|
||||
int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex);
|
||||
int t3_phy_lasi_intr_enable(struct cphy *phy);
|
||||
int t3_phy_lasi_intr_disable(struct cphy *phy);
|
||||
int t3_phy_lasi_intr_clear(struct cphy *phy);
|
||||
int t3_phy_lasi_intr_handler(struct cphy *phy);
|
||||
|
||||
void t3_intr_enable(struct adapter *adapter);
|
||||
void t3_intr_disable(struct adapter *adapter);
|
||||
|
|
@ -698,6 +726,7 @@ int t3_check_fw_version(struct adapter *adapter, int *must_load);
|
|||
int t3_init_hw(struct adapter *adapter, u32 fw_params);
|
||||
void mac_prep(struct cmac *mac, struct adapter *adapter, int index);
|
||||
void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
|
||||
int t3_reset_adapter(struct adapter *adapter);
|
||||
int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
|
||||
int reset);
|
||||
int t3_replay_prep_adapter(struct adapter *adapter);
|
||||
|
|
@ -774,14 +803,16 @@ int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4]);
|
|||
int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
|
||||
unsigned int credits);
|
||||
|
||||
void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *mdio_ops);
|
||||
void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *mdio_ops);
|
||||
void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *mdio_ops);
|
||||
void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
|
||||
const struct mdio_ops *mdio_ops);
|
||||
void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *mdio_ops);
|
||||
int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *mdio_ops);
|
||||
int t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *mdio_ops);
|
||||
int t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *mdio_ops);
|
||||
int t3_ael2005_phy_prep(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *mdio_ops);
|
||||
int t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
|
||||
const struct mdio_ops *mdio_ops);
|
||||
int t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *mdio_ops);
|
||||
#endif /* __CHELSIO_COMMON_H */
|
||||
|
|
|
|||
|
|
@ -92,6 +92,8 @@ struct ch_qset_params {
|
|||
int32_t polling;
|
||||
int32_t lro;
|
||||
int32_t cong_thres;
|
||||
int32_t vector;
|
||||
int32_t qnum;
|
||||
};
|
||||
|
||||
struct ch_pktsched_params {
|
||||
|
|
|
|||
|
|
@ -208,6 +208,31 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* t3_os_phymod_changed - handle PHY module changes
|
||||
* @phy: the PHY reporting the module change
|
||||
* @mod_type: new module type
|
||||
*
|
||||
* This is the OS-dependent handler for PHY module changes. It is
|
||||
* invoked when a PHY module is removed or inserted for any OS-specific
|
||||
* processing.
|
||||
*/
|
||||
void t3_os_phymod_changed(struct adapter *adap, int port_id)
|
||||
{
|
||||
static const char *mod_str[] = {
|
||||
NULL, "SR", "LR", "LRM", "TWINAX", "TWINAX", "unknown"
|
||||
};
|
||||
|
||||
const struct net_device *dev = adap->port[port_id];
|
||||
const struct port_info *pi = netdev_priv(dev);
|
||||
|
||||
if (pi->phy.modtype == phy_modtype_none)
|
||||
printk(KERN_INFO "%s: PHY module unplugged\n", dev->name);
|
||||
else
|
||||
printk(KERN_INFO "%s: %s PHY module inserted\n", dev->name,
|
||||
mod_str[pi->phy.modtype]);
|
||||
}
|
||||
|
||||
static void cxgb_set_rxmode(struct net_device *dev)
|
||||
{
|
||||
struct t3_rx_mode rm;
|
||||
|
|
@ -274,10 +299,10 @@ static void name_msix_vecs(struct adapter *adap)
|
|||
|
||||
for (i = 0; i < pi->nqsets; i++, msi_idx++) {
|
||||
snprintf(adap->msix_info[msi_idx].desc, n,
|
||||
"%s (queue %d)", d->name, i);
|
||||
"%s-%d", d->name, pi->first_qset + i);
|
||||
adap->msix_info[msi_idx].desc[n] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int request_msix_data_irqs(struct adapter *adap)
|
||||
|
|
@ -306,6 +331,22 @@ static int request_msix_data_irqs(struct adapter *adap)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void free_irq_resources(struct adapter *adapter)
|
||||
{
|
||||
if (adapter->flags & USING_MSIX) {
|
||||
int i, n = 0;
|
||||
|
||||
free_irq(adapter->msix_info[0].vec, adapter);
|
||||
for_each_port(adapter, i)
|
||||
n += adap2pinfo(adapter, i)->nqsets;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
free_irq(adapter->msix_info[i + 1].vec,
|
||||
&adapter->sge.qs[i]);
|
||||
} else
|
||||
free_irq(adapter->pdev->irq, adapter);
|
||||
}
|
||||
|
||||
static int await_mgmt_replies(struct adapter *adap, unsigned long init_cnt,
|
||||
unsigned long n)
|
||||
{
|
||||
|
|
@ -473,12 +514,16 @@ static int setup_sge_qsets(struct adapter *adap)
|
|||
struct port_info *pi = netdev_priv(dev);
|
||||
|
||||
pi->qs = &adap->sge.qs[pi->first_qset];
|
||||
for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
|
||||
for (j = pi->first_qset; j < pi->first_qset + pi->nqsets;
|
||||
++j, ++qset_idx) {
|
||||
if (!pi->rx_csum_offload)
|
||||
adap->params.sge.qset[qset_idx].lro = 0;
|
||||
err = t3_sge_alloc_qset(adap, qset_idx, 1,
|
||||
(adap->flags & USING_MSIX) ? qset_idx + 1 :
|
||||
irq_idx,
|
||||
&adap->params.sge.qset[qset_idx], ntxq, dev);
|
||||
if (err) {
|
||||
t3_stop_sge_timers(adap);
|
||||
t3_free_sge_resources(adap);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -739,11 +784,12 @@ static void init_port_mtus(struct adapter *adapter)
|
|||
t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
|
||||
}
|
||||
|
||||
static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
|
||||
static int send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
|
||||
int hi, int port)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct mngt_pktsched_wr *req;
|
||||
int ret;
|
||||
|
||||
skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
|
||||
req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
|
||||
|
|
@ -754,20 +800,28 @@ static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
|
|||
req->min = lo;
|
||||
req->max = hi;
|
||||
req->binding = port;
|
||||
t3_mgmt_tx(adap, skb);
|
||||
ret = t3_mgmt_tx(adap, skb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void bind_qsets(struct adapter *adap)
|
||||
static int bind_qsets(struct adapter *adap)
|
||||
{
|
||||
int i, j;
|
||||
int i, j, err = 0;
|
||||
|
||||
for_each_port(adap, i) {
|
||||
const struct port_info *pi = adap2pinfo(adap, i);
|
||||
|
||||
for (j = 0; j < pi->nqsets; ++j)
|
||||
send_pktsched_cmd(adap, 1, pi->first_qset + j, -1,
|
||||
-1, i);
|
||||
for (j = 0; j < pi->nqsets; ++j) {
|
||||
int ret = send_pktsched_cmd(adap, 1,
|
||||
pi->first_qset + j, -1,
|
||||
-1, i);
|
||||
if (ret)
|
||||
err = ret;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#define FW_FNAME "t3fw-%d.%d.%d.bin"
|
||||
|
|
@ -891,6 +945,13 @@ static int cxgb_up(struct adapter *adap)
|
|||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear interrupts now to catch errors if t3_init_hw fails.
|
||||
* We clear them again later as initialization may trigger
|
||||
* conditions that can interrupt.
|
||||
*/
|
||||
t3_intr_clear(adap);
|
||||
|
||||
err = t3_init_hw(adap, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
|
|
@ -946,9 +1007,16 @@ static int cxgb_up(struct adapter *adap)
|
|||
t3_write_reg(adap, A_TP_INT_ENABLE, 0x7fbfffff);
|
||||
}
|
||||
|
||||
if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
|
||||
bind_qsets(adap);
|
||||
adap->flags |= QUEUES_BOUND;
|
||||
if (!(adap->flags & QUEUES_BOUND)) {
|
||||
err = bind_qsets(adap);
|
||||
if (err) {
|
||||
CH_ERR(adap, "failed to bind qsets, err %d\n", err);
|
||||
t3_intr_disable(adap);
|
||||
free_irq_resources(adap);
|
||||
goto out;
|
||||
}
|
||||
adap->flags |= QUEUES_BOUND;
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
|
|
@ -967,19 +1035,7 @@ static void cxgb_down(struct adapter *adapter)
|
|||
t3_intr_disable(adapter);
|
||||
spin_unlock_irq(&adapter->work_lock);
|
||||
|
||||
if (adapter->flags & USING_MSIX) {
|
||||
int i, n = 0;
|
||||
|
||||
free_irq(adapter->msix_info[0].vec, adapter);
|
||||
for_each_port(adapter, i)
|
||||
n += adap2pinfo(adapter, i)->nqsets;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
free_irq(adapter->msix_info[i + 1].vec,
|
||||
&adapter->sge.qs[i]);
|
||||
} else
|
||||
free_irq(adapter->pdev->irq, adapter);
|
||||
|
||||
free_irq_resources(adapter);
|
||||
flush_workqueue(cxgb3_wq); /* wait for external IRQ handler */
|
||||
quiesce_rx(adapter);
|
||||
}
|
||||
|
|
@ -1100,9 +1156,9 @@ static int cxgb_close(struct net_device *dev)
|
|||
netif_carrier_off(dev);
|
||||
t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
|
||||
|
||||
spin_lock(&adapter->work_lock); /* sync with update task */
|
||||
spin_lock_irq(&adapter->work_lock); /* sync with update task */
|
||||
clear_bit(pi->port_id, &adapter->open_device_map);
|
||||
spin_unlock(&adapter->work_lock);
|
||||
spin_unlock_irq(&adapter->work_lock);
|
||||
|
||||
if (!(adapter->open_device_map & PORT_MASK))
|
||||
cancel_rearming_delayed_workqueue(cxgb3_wq,
|
||||
|
|
@ -1284,8 +1340,8 @@ static unsigned long collect_sge_port_stats(struct adapter *adapter,
|
|||
int i;
|
||||
unsigned long tot = 0;
|
||||
|
||||
for (i = 0; i < p->nqsets; ++i)
|
||||
tot += adapter->sge.qs[i + p->first_qset].port_stats[idx];
|
||||
for (i = p->first_qset; i < p->first_qset + p->nqsets; ++i)
|
||||
tot += adapter->sge.qs[i].port_stats[idx];
|
||||
return tot;
|
||||
}
|
||||
|
||||
|
|
@ -1485,11 +1541,22 @@ static int speed_duplex_to_caps(int speed, int duplex)
|
|||
|
||||
static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
|
||||
{
|
||||
int cap;
|
||||
struct port_info *p = netdev_priv(dev);
|
||||
struct link_config *lc = &p->link_config;
|
||||
|
||||
if (!(lc->supported & SUPPORTED_Autoneg))
|
||||
return -EOPNOTSUPP; /* can't change speed/duplex */
|
||||
if (!(lc->supported & SUPPORTED_Autoneg)) {
|
||||
/*
|
||||
* PHY offers a single speed/duplex. See if that's what's
|
||||
* being requested.
|
||||
*/
|
||||
if (cmd->autoneg == AUTONEG_DISABLE) {
|
||||
cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
|
||||
if (lc->supported & cap)
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cmd->autoneg == AUTONEG_DISABLE) {
|
||||
int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
|
||||
|
|
@ -1568,8 +1635,10 @@ static int set_rx_csum(struct net_device *dev, u32 data)
|
|||
struct adapter *adap = p->adapter;
|
||||
int i;
|
||||
|
||||
for (i = p->first_qset; i < p->first_qset + p->nqsets; i++)
|
||||
for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
|
||||
adap->params.sge.qset[i].lro = 0;
|
||||
adap->sge.qs[i].lro_enabled = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1775,6 +1844,8 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
|||
int i;
|
||||
struct qset_params *q;
|
||||
struct ch_qset_params t;
|
||||
int q1 = pi->first_qset;
|
||||
int nqsets = pi->nqsets;
|
||||
|
||||
if (!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
|
@ -1797,6 +1868,16 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
|||
|| !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
|
||||
MAX_RSPQ_ENTRIES))
|
||||
return -EINVAL;
|
||||
|
||||
if ((adapter->flags & FULL_INIT_DONE) && t.lro > 0)
|
||||
for_each_port(adapter, i) {
|
||||
pi = adap2pinfo(adapter, i);
|
||||
if (t.qset_idx >= pi->first_qset &&
|
||||
t.qset_idx < pi->first_qset + pi->nqsets &&
|
||||
!pi->rx_csum_offload)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((adapter->flags & FULL_INIT_DONE) &&
|
||||
(t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
|
||||
t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
|
||||
|
|
@ -1804,6 +1885,20 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
|||
t.polling >= 0 || t.cong_thres >= 0))
|
||||
return -EBUSY;
|
||||
|
||||
/* Allow setting of any available qset when offload enabled */
|
||||
if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
|
||||
q1 = 0;
|
||||
for_each_port(adapter, i) {
|
||||
pi = adap2pinfo(adapter, i);
|
||||
nqsets += pi->first_qset + pi->nqsets;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.qset_idx < q1)
|
||||
return -EINVAL;
|
||||
if (t.qset_idx > q1 + nqsets - 1)
|
||||
return -EINVAL;
|
||||
|
||||
q = &adapter->params.sge.qset[t.qset_idx];
|
||||
|
||||
if (t.rspq_size >= 0)
|
||||
|
|
@ -1853,13 +1948,26 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
|||
case CHELSIO_GET_QSET_PARAMS:{
|
||||
struct qset_params *q;
|
||||
struct ch_qset_params t;
|
||||
int q1 = pi->first_qset;
|
||||
int nqsets = pi->nqsets;
|
||||
int i;
|
||||
|
||||
if (copy_from_user(&t, useraddr, sizeof(t)))
|
||||
return -EFAULT;
|
||||
if (t.qset_idx >= SGE_QSETS)
|
||||
|
||||
/* Display qsets for all ports when offload enabled */
|
||||
if (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map)) {
|
||||
q1 = 0;
|
||||
for_each_port(adapter, i) {
|
||||
pi = adap2pinfo(adapter, i);
|
||||
nqsets = pi->first_qset + pi->nqsets;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.qset_idx >= nqsets)
|
||||
return -EINVAL;
|
||||
|
||||
q = &adapter->params.sge.qset[t.qset_idx];
|
||||
q = &adapter->params.sge.qset[q1 + t.qset_idx];
|
||||
t.rspq_size = q->rspq_size;
|
||||
t.txq_size[0] = q->txq_size[0];
|
||||
t.txq_size[1] = q->txq_size[1];
|
||||
|
|
@ -1870,6 +1978,12 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
|
|||
t.lro = q->lro;
|
||||
t.intr_lat = q->coalesce_usecs;
|
||||
t.cong_thres = q->cong_thres;
|
||||
t.qnum = q1;
|
||||
|
||||
if (adapter->flags & USING_MSIX)
|
||||
t.vector = adapter->msix_info[q1 + t.qset_idx + 1].vec;
|
||||
else
|
||||
t.vector = adapter->pdev->irq;
|
||||
|
||||
if (copy_to_user(useraddr, &t, sizeof(t)))
|
||||
return -EFAULT;
|
||||
|
|
@ -2117,7 +2231,7 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
|
|||
mmd = data->phy_id >> 8;
|
||||
if (!mmd)
|
||||
mmd = MDIO_DEV_PCS;
|
||||
else if (mmd > MDIO_DEV_XGXS)
|
||||
else if (mmd > MDIO_DEV_VEND2)
|
||||
return -EINVAL;
|
||||
|
||||
ret =
|
||||
|
|
@ -2143,7 +2257,7 @@ static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
|
|||
mmd = data->phy_id >> 8;
|
||||
if (!mmd)
|
||||
mmd = MDIO_DEV_PCS;
|
||||
else if (mmd > MDIO_DEV_XGXS)
|
||||
else if (mmd > MDIO_DEV_VEND2)
|
||||
return -EINVAL;
|
||||
|
||||
ret =
|
||||
|
|
@ -2215,8 +2329,8 @@ static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < p->nqsets; i++) {
|
||||
struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq;
|
||||
for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) {
|
||||
struct sge_rspq *q = &adap->sge.qs[i].rspq;
|
||||
|
||||
spin_lock_irq(&q->lock);
|
||||
spin_unlock_irq(&q->lock);
|
||||
|
|
@ -2290,7 +2404,7 @@ static void check_link_status(struct adapter *adapter)
|
|||
struct net_device *dev = adapter->port[i];
|
||||
struct port_info *p = netdev_priv(dev);
|
||||
|
||||
if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev))
|
||||
if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev))
|
||||
t3_link_changed(adapter, i);
|
||||
}
|
||||
}
|
||||
|
|
@ -2355,10 +2469,10 @@ static void t3_adap_check_task(struct work_struct *work)
|
|||
check_t3b2_mac(adapter);
|
||||
|
||||
/* Schedule the next check update if any port is active. */
|
||||
spin_lock(&adapter->work_lock);
|
||||
spin_lock_irq(&adapter->work_lock);
|
||||
if (adapter->open_device_map & PORT_MASK)
|
||||
schedule_chk_task(adapter);
|
||||
spin_unlock(&adapter->work_lock);
|
||||
spin_unlock_irq(&adapter->work_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2403,6 +2517,96 @@ void t3_os_ext_intr_handler(struct adapter *adapter)
|
|||
spin_unlock(&adapter->work_lock);
|
||||
}
|
||||
|
||||
static int t3_adapter_error(struct adapter *adapter, int reset)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
/* Stop all ports */
|
||||
for_each_port(adapter, i) {
|
||||
struct net_device *netdev = adapter->port[i];
|
||||
|
||||
if (netif_running(netdev))
|
||||
cxgb_close(netdev);
|
||||
}
|
||||
|
||||
if (is_offload(adapter) &&
|
||||
test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
|
||||
offload_close(&adapter->tdev);
|
||||
|
||||
/* Stop SGE timers */
|
||||
t3_stop_sge_timers(adapter);
|
||||
|
||||
adapter->flags &= ~FULL_INIT_DONE;
|
||||
|
||||
if (reset)
|
||||
ret = t3_reset_adapter(adapter);
|
||||
|
||||
pci_disable_device(adapter->pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int t3_reenable_adapter(struct adapter *adapter)
|
||||
{
|
||||
if (pci_enable_device(adapter->pdev)) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"Cannot re-enable PCI device after reset.\n");
|
||||
goto err;
|
||||
}
|
||||
pci_set_master(adapter->pdev);
|
||||
pci_restore_state(adapter->pdev);
|
||||
|
||||
/* Free sge resources */
|
||||
t3_free_sge_resources(adapter);
|
||||
|
||||
if (t3_replay_prep_adapter(adapter))
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void t3_resume_ports(struct adapter *adapter)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Restart the ports */
|
||||
for_each_port(adapter, i) {
|
||||
struct net_device *netdev = adapter->port[i];
|
||||
|
||||
if (netif_running(netdev)) {
|
||||
if (cxgb_open(netdev)) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"can't bring device back up"
|
||||
" after reset\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* processes a fatal error.
|
||||
* Bring the ports down, reset the chip, bring the ports back up.
|
||||
*/
|
||||
static void fatal_error_task(struct work_struct *work)
|
||||
{
|
||||
struct adapter *adapter = container_of(work, struct adapter,
|
||||
fatal_error_handler_task);
|
||||
int err = 0;
|
||||
|
||||
rtnl_lock();
|
||||
err = t3_adapter_error(adapter, 1);
|
||||
if (!err)
|
||||
err = t3_reenable_adapter(adapter);
|
||||
if (!err)
|
||||
t3_resume_ports(adapter);
|
||||
|
||||
CH_ALERT(adapter, "adapter reset %s\n", err ? "failed" : "succeeded");
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
void t3_fatal_err(struct adapter *adapter)
|
||||
{
|
||||
unsigned int fw_status[4];
|
||||
|
|
@ -2413,7 +2617,11 @@ void t3_fatal_err(struct adapter *adapter)
|
|||
t3_write_reg(adapter, A_XGM_RX_CTRL, 0);
|
||||
t3_write_reg(adapter, XGM_REG(A_XGM_TX_CTRL, 1), 0);
|
||||
t3_write_reg(adapter, XGM_REG(A_XGM_RX_CTRL, 1), 0);
|
||||
|
||||
spin_lock(&adapter->work_lock);
|
||||
t3_intr_disable(adapter);
|
||||
queue_work(cxgb3_wq, &adapter->fatal_error_handler_task);
|
||||
spin_unlock(&adapter->work_lock);
|
||||
}
|
||||
CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
|
||||
if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
|
||||
|
|
@ -2435,23 +2643,9 @@ static pci_ers_result_t t3_io_error_detected(struct pci_dev *pdev,
|
|||
pci_channel_state_t state)
|
||||
{
|
||||
struct adapter *adapter = pci_get_drvdata(pdev);
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
/* Stop all ports */
|
||||
for_each_port(adapter, i) {
|
||||
struct net_device *netdev = adapter->port[i];
|
||||
|
||||
if (netif_running(netdev))
|
||||
cxgb_close(netdev);
|
||||
}
|
||||
|
||||
if (is_offload(adapter) &&
|
||||
test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
|
||||
offload_close(&adapter->tdev);
|
||||
|
||||
adapter->flags &= ~FULL_INIT_DONE;
|
||||
|
||||
pci_disable_device(pdev);
|
||||
ret = t3_adapter_error(adapter, 0);
|
||||
|
||||
/* Request a slot reset. */
|
||||
return PCI_ERS_RESULT_NEED_RESET;
|
||||
|
|
@ -2467,22 +2661,9 @@ static pci_ers_result_t t3_io_slot_reset(struct pci_dev *pdev)
|
|||
{
|
||||
struct adapter *adapter = pci_get_drvdata(pdev);
|
||||
|
||||
if (pci_enable_device(pdev)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Cannot re-enable PCI device after reset.\n");
|
||||
goto err;
|
||||
}
|
||||
pci_set_master(pdev);
|
||||
pci_restore_state(pdev);
|
||||
if (!t3_reenable_adapter(adapter))
|
||||
return PCI_ERS_RESULT_RECOVERED;
|
||||
|
||||
/* Free sge resources */
|
||||
t3_free_sge_resources(adapter);
|
||||
|
||||
if (t3_replay_prep_adapter(adapter))
|
||||
goto err;
|
||||
|
||||
return PCI_ERS_RESULT_RECOVERED;
|
||||
err:
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
}
|
||||
|
||||
|
|
@ -2496,22 +2677,8 @@ err:
|
|||
static void t3_io_resume(struct pci_dev *pdev)
|
||||
{
|
||||
struct adapter *adapter = pci_get_drvdata(pdev);
|
||||
int i;
|
||||
|
||||
/* Restart the ports */
|
||||
for_each_port(adapter, i) {
|
||||
struct net_device *netdev = adapter->port[i];
|
||||
|
||||
if (netif_running(netdev)) {
|
||||
if (cxgb_open(netdev)) {
|
||||
dev_err(&pdev->dev,
|
||||
"can't bring device back up"
|
||||
" after reset\n");
|
||||
continue;
|
||||
}
|
||||
netif_device_attach(netdev);
|
||||
}
|
||||
}
|
||||
t3_resume_ports(adapter);
|
||||
}
|
||||
|
||||
static struct pci_error_handlers t3_err_handler = {
|
||||
|
|
@ -2520,6 +2687,42 @@ static struct pci_error_handlers t3_err_handler = {
|
|||
.resume = t3_io_resume,
|
||||
};
|
||||
|
||||
/*
|
||||
* Set the number of qsets based on the number of CPUs and the number of ports,
|
||||
* not to exceed the number of available qsets, assuming there are enough qsets
|
||||
* per port in HW.
|
||||
*/
|
||||
static void set_nqsets(struct adapter *adap)
|
||||
{
|
||||
int i, j = 0;
|
||||
int num_cpus = num_online_cpus();
|
||||
int hwports = adap->params.nports;
|
||||
int nqsets = SGE_QSETS;
|
||||
|
||||
if (adap->params.rev > 0) {
|
||||
if (hwports == 2 &&
|
||||
(hwports * nqsets > SGE_QSETS ||
|
||||
num_cpus >= nqsets / hwports))
|
||||
nqsets /= hwports;
|
||||
if (nqsets > num_cpus)
|
||||
nqsets = num_cpus;
|
||||
if (nqsets < 1 || hwports == 4)
|
||||
nqsets = 1;
|
||||
} else
|
||||
nqsets = 1;
|
||||
|
||||
for_each_port(adap, i) {
|
||||
struct port_info *pi = adap2pinfo(adap, i);
|
||||
|
||||
pi->first_qset = j;
|
||||
pi->nqsets = nqsets;
|
||||
j = pi->first_qset + nqsets;
|
||||
|
||||
dev_info(&adap->pdev->dev,
|
||||
"Port %d using %d queue sets.\n", i, nqsets);
|
||||
}
|
||||
}
|
||||
|
||||
static int __devinit cxgb_enable_msix(struct adapter *adap)
|
||||
{
|
||||
struct msix_entry entries[SGE_QSETS + 1];
|
||||
|
|
@ -2564,7 +2767,7 @@ static void __devinit print_port_info(struct adapter *adap,
|
|||
if (!test_bit(i, &adap->registered_device_map))
|
||||
continue;
|
||||
printk(KERN_INFO "%s: %s %s %sNIC (rev %d) %s%s\n",
|
||||
dev->name, ai->desc, pi->port_type->desc,
|
||||
dev->name, ai->desc, pi->phy.desc,
|
||||
is_offload(adap) ? "R" : "", adap->params.rev, buf,
|
||||
(adap->flags & USING_MSIX) ? " MSI-X" :
|
||||
(adap->flags & USING_MSI) ? " MSI" : "");
|
||||
|
|
@ -2660,6 +2863,7 @@ static int __devinit init_one(struct pci_dev *pdev,
|
|||
|
||||
INIT_LIST_HEAD(&adapter->adapter_list);
|
||||
INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
|
||||
INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
|
||||
INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
|
||||
|
||||
for (i = 0; i < ai->nports; ++i) {
|
||||
|
|
@ -2677,9 +2881,6 @@ static int __devinit init_one(struct pci_dev *pdev,
|
|||
pi = netdev_priv(netdev);
|
||||
pi->adapter = adapter;
|
||||
pi->rx_csum_offload = 1;
|
||||
pi->nqsets = 1;
|
||||
pi->first_qset = i;
|
||||
pi->activity = 0;
|
||||
pi->port_id = i;
|
||||
netif_carrier_off(netdev);
|
||||
netdev->irq = pdev->irq;
|
||||
|
|
@ -2756,6 +2957,8 @@ static int __devinit init_one(struct pci_dev *pdev,
|
|||
else if (msi > 0 && pci_enable_msi(pdev) == 0)
|
||||
adapter->flags |= USING_MSI;
|
||||
|
||||
set_nqsets(adapter);
|
||||
|
||||
err = sysfs_create_group(&adapter->port[0]->dev.kobj,
|
||||
&cxgb3_attr_group);
|
||||
|
||||
|
|
@ -2801,6 +3004,7 @@ static void __devexit remove_one(struct pci_dev *pdev)
|
|||
if (test_bit(i, &adapter->registered_device_map))
|
||||
unregister_netdev(adapter->port[i]);
|
||||
|
||||
t3_stop_sge_timers(adapter);
|
||||
t3_free_sge_resources(adapter);
|
||||
cxgb_disable_msi(adapter);
|
||||
|
||||
|
|
|
|||
|
|
@ -1018,7 +1018,7 @@ static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
|
|||
|
||||
skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
printk(KERN_ERR "%s: cannot allocate skb!\n", __FUNCTION__);
|
||||
printk(KERN_ERR "%s: cannot allocate skb!\n", __func__);
|
||||
return;
|
||||
}
|
||||
skb->priority = CPL_PRIORITY_CONTROL;
|
||||
|
|
@ -1049,14 +1049,14 @@ void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
|
|||
return;
|
||||
if (!is_offloading(newdev)) {
|
||||
printk(KERN_WARNING "%s: Redirect to non-offload "
|
||||
"device ignored.\n", __FUNCTION__);
|
||||
"device ignored.\n", __func__);
|
||||
return;
|
||||
}
|
||||
tdev = dev2t3cdev(olddev);
|
||||
BUG_ON(!tdev);
|
||||
if (tdev != dev2t3cdev(newdev)) {
|
||||
printk(KERN_WARNING "%s: Redirect to different "
|
||||
"offload device ignored.\n", __FUNCTION__);
|
||||
"offload device ignored.\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1064,7 +1064,7 @@ void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
|
|||
e = t3_l2t_get(tdev, new->neighbour, newdev);
|
||||
if (!e) {
|
||||
printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb,
|
|||
struct l2t_entry *e)
|
||||
{
|
||||
struct cpl_l2t_write_req *req;
|
||||
struct sk_buff *tmp;
|
||||
|
||||
if (!skb) {
|
||||
skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
|
||||
|
|
@ -103,13 +104,11 @@ static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb,
|
|||
memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));
|
||||
skb->priority = CPL_PRIORITY_CONTROL;
|
||||
cxgb3_ofld_send(dev, skb);
|
||||
while (e->arpq_head) {
|
||||
skb = e->arpq_head;
|
||||
e->arpq_head = skb->next;
|
||||
skb->next = NULL;
|
||||
|
||||
skb_queue_walk_safe(&e->arpq, skb, tmp) {
|
||||
__skb_unlink(skb, &e->arpq);
|
||||
cxgb3_ofld_send(dev, skb);
|
||||
}
|
||||
e->arpq_tail = NULL;
|
||||
e->state = L2T_STATE_VALID;
|
||||
|
||||
return 0;
|
||||
|
|
@ -121,12 +120,7 @@ static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb,
|
|||
*/
|
||||
static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb)
|
||||
{
|
||||
skb->next = NULL;
|
||||
if (e->arpq_head)
|
||||
e->arpq_tail->next = skb;
|
||||
else
|
||||
e->arpq_head = skb;
|
||||
e->arpq_tail = skb;
|
||||
__skb_queue_tail(&e->arpq, skb);
|
||||
}
|
||||
|
||||
int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb,
|
||||
|
|
@ -167,7 +161,7 @@ again:
|
|||
break;
|
||||
|
||||
spin_lock_bh(&e->lock);
|
||||
if (e->arpq_head)
|
||||
if (!skb_queue_empty(&e->arpq))
|
||||
setup_l2e_send_pending(dev, skb, e);
|
||||
else /* we lost the race */
|
||||
__kfree_skb(skb);
|
||||
|
|
@ -357,14 +351,14 @@ EXPORT_SYMBOL(t3_l2t_get);
|
|||
* XXX: maybe we should abandon the latter behavior and just require a failure
|
||||
* handler.
|
||||
*/
|
||||
static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq)
|
||||
static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff_head *arpq)
|
||||
{
|
||||
while (arpq) {
|
||||
struct sk_buff *skb = arpq;
|
||||
struct sk_buff *skb, *tmp;
|
||||
|
||||
skb_queue_walk_safe(arpq, skb, tmp) {
|
||||
struct l2t_skb_cb *cb = L2T_SKB_CB(skb);
|
||||
|
||||
arpq = skb->next;
|
||||
skb->next = NULL;
|
||||
__skb_unlink(skb, arpq);
|
||||
if (cb->arp_failure_handler)
|
||||
cb->arp_failure_handler(dev, skb);
|
||||
else
|
||||
|
|
@ -378,8 +372,8 @@ static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq)
|
|||
*/
|
||||
void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh)
|
||||
{
|
||||
struct sk_buff_head arpq;
|
||||
struct l2t_entry *e;
|
||||
struct sk_buff *arpq = NULL;
|
||||
struct l2t_data *d = L2DATA(dev);
|
||||
u32 addr = *(u32 *) neigh->primary_key;
|
||||
int ifidx = neigh->dev->ifindex;
|
||||
|
|
@ -395,6 +389,8 @@ void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh)
|
|||
return;
|
||||
|
||||
found:
|
||||
__skb_queue_head_init(&arpq);
|
||||
|
||||
read_unlock(&d->lock);
|
||||
if (atomic_read(&e->refcnt)) {
|
||||
if (neigh != e->neigh)
|
||||
|
|
@ -402,8 +398,7 @@ found:
|
|||
|
||||
if (e->state == L2T_STATE_RESOLVING) {
|
||||
if (neigh->nud_state & NUD_FAILED) {
|
||||
arpq = e->arpq_head;
|
||||
e->arpq_head = e->arpq_tail = NULL;
|
||||
skb_queue_splice_init(&e->arpq, &arpq);
|
||||
} else if (neigh->nud_state & (NUD_CONNECTED|NUD_STALE))
|
||||
setup_l2e_send_pending(dev, NULL, e);
|
||||
} else {
|
||||
|
|
@ -415,8 +410,8 @@ found:
|
|||
}
|
||||
spin_unlock_bh(&e->lock);
|
||||
|
||||
if (arpq)
|
||||
handle_failed_resolution(dev, arpq);
|
||||
if (!skb_queue_empty(&arpq))
|
||||
handle_failed_resolution(dev, &arpq);
|
||||
}
|
||||
|
||||
struct l2t_data *t3_init_l2t(unsigned int l2t_capacity)
|
||||
|
|
|
|||
|
|
@ -64,8 +64,7 @@ struct l2t_entry {
|
|||
struct neighbour *neigh; /* associated neighbour */
|
||||
struct l2t_entry *first; /* start of hash chain */
|
||||
struct l2t_entry *next; /* next l2t_entry on chain */
|
||||
struct sk_buff *arpq_head; /* queue of packets awaiting resolution */
|
||||
struct sk_buff *arpq_tail;
|
||||
struct sk_buff_head arpq; /* queue of packets awaiting resolution */
|
||||
spinlock_t lock;
|
||||
atomic_t refcnt; /* entry reference count */
|
||||
u8 dmac[6]; /* neighbour's MAC address */
|
||||
|
|
|
|||
|
|
@ -573,6 +573,10 @@
|
|||
#define V_GPIO10(x) ((x) << S_GPIO10)
|
||||
#define F_GPIO10 V_GPIO10(1U)
|
||||
|
||||
#define S_GPIO9 9
|
||||
#define V_GPIO9(x) ((x) << S_GPIO9)
|
||||
#define F_GPIO9 V_GPIO9(1U)
|
||||
|
||||
#define S_GPIO7 7
|
||||
#define V_GPIO7(x) ((x) << S_GPIO7)
|
||||
#define F_GPIO7 V_GPIO7(1U)
|
||||
|
|
|
|||
|
|
@ -351,7 +351,8 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
|
|||
pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
|
||||
q->buf_size, PCI_DMA_FROMDEVICE);
|
||||
if (q->use_pages) {
|
||||
put_page(d->pg_chunk.page);
|
||||
if (d->pg_chunk.page)
|
||||
put_page(d->pg_chunk.page);
|
||||
d->pg_chunk.page = NULL;
|
||||
} else {
|
||||
kfree_skb(d->skb);
|
||||
|
|
@ -583,7 +584,7 @@ static void t3_reset_qset(struct sge_qset *q)
|
|||
memset(q->fl, 0, sizeof(struct sge_fl) * SGE_RXQ_PER_SET);
|
||||
memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET);
|
||||
q->txq_stopped = 0;
|
||||
memset(&q->tx_reclaim_timer, 0, sizeof(q->tx_reclaim_timer));
|
||||
q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */
|
||||
kfree(q->lro_frag_tbl);
|
||||
q->lro_nfrags = q->lro_frag_len = 0;
|
||||
}
|
||||
|
|
@ -603,9 +604,6 @@ static void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
|
|||
int i;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
|
||||
if (q->tx_reclaim_timer.function)
|
||||
del_timer_sync(&q->tx_reclaim_timer);
|
||||
|
||||
for (i = 0; i < SGE_RXQ_PER_SET; ++i)
|
||||
if (q->fl[i].desc) {
|
||||
spin_lock_irq(&adapter->sge.reg_lock);
|
||||
|
|
@ -1704,16 +1702,15 @@ int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
|
|||
*/
|
||||
static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb)
|
||||
{
|
||||
skb->next = skb->prev = NULL;
|
||||
if (q->rx_tail)
|
||||
q->rx_tail->next = skb;
|
||||
else {
|
||||
int was_empty = skb_queue_empty(&q->rx_queue);
|
||||
|
||||
__skb_queue_tail(&q->rx_queue, skb);
|
||||
|
||||
if (was_empty) {
|
||||
struct sge_qset *qs = rspq_to_qset(q);
|
||||
|
||||
napi_schedule(&qs->napi);
|
||||
q->rx_head = skb;
|
||||
}
|
||||
q->rx_tail = skb;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1754,26 +1751,29 @@ static int ofld_poll(struct napi_struct *napi, int budget)
|
|||
int work_done = 0;
|
||||
|
||||
while (work_done < budget) {
|
||||
struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE];
|
||||
struct sk_buff *skb, *tmp, *skbs[RX_BUNDLE_SIZE];
|
||||
struct sk_buff_head queue;
|
||||
int ngathered;
|
||||
|
||||
spin_lock_irq(&q->lock);
|
||||
head = q->rx_head;
|
||||
if (!head) {
|
||||
__skb_queue_head_init(&queue);
|
||||
skb_queue_splice_init(&q->rx_queue, &queue);
|
||||
if (skb_queue_empty(&queue)) {
|
||||
napi_complete(napi);
|
||||
spin_unlock_irq(&q->lock);
|
||||
return work_done;
|
||||
}
|
||||
|
||||
tail = q->rx_tail;
|
||||
q->rx_head = q->rx_tail = NULL;
|
||||
spin_unlock_irq(&q->lock);
|
||||
|
||||
for (ngathered = 0; work_done < budget && head; work_done++) {
|
||||
prefetch(head->data);
|
||||
skbs[ngathered] = head;
|
||||
head = head->next;
|
||||
skbs[ngathered]->next = NULL;
|
||||
ngathered = 0;
|
||||
skb_queue_walk_safe(&queue, skb, tmp) {
|
||||
if (work_done >= budget)
|
||||
break;
|
||||
work_done++;
|
||||
|
||||
__skb_unlink(skb, &queue);
|
||||
prefetch(skb->data);
|
||||
skbs[ngathered] = skb;
|
||||
if (++ngathered == RX_BUNDLE_SIZE) {
|
||||
q->offload_bundles++;
|
||||
adapter->tdev.recv(&adapter->tdev, skbs,
|
||||
|
|
@ -1781,12 +1781,10 @@ static int ofld_poll(struct napi_struct *napi, int budget)
|
|||
ngathered = 0;
|
||||
}
|
||||
}
|
||||
if (head) { /* splice remaining packets back onto Rx queue */
|
||||
if (!skb_queue_empty(&queue)) {
|
||||
/* splice remaining packets back onto Rx queue */
|
||||
spin_lock_irq(&q->lock);
|
||||
tail->next = q->rx_head;
|
||||
if (!q->rx_head)
|
||||
q->rx_tail = tail;
|
||||
q->rx_head = head;
|
||||
skb_queue_splice(&queue, &q->rx_queue);
|
||||
spin_unlock_irq(&q->lock);
|
||||
}
|
||||
deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered);
|
||||
|
|
@ -1937,38 +1935,6 @@ static inline int lro_frame_ok(const struct cpl_rx_pkt *p)
|
|||
eh->h_proto == htons(ETH_P_IP) && ih->ihl == (sizeof(*ih) >> 2);
|
||||
}
|
||||
|
||||
#define TCP_FLAG_MASK (TCP_FLAG_CWR | TCP_FLAG_ECE | TCP_FLAG_URG |\
|
||||
TCP_FLAG_ACK | TCP_FLAG_PSH | TCP_FLAG_RST |\
|
||||
TCP_FLAG_SYN | TCP_FLAG_FIN)
|
||||
#define TSTAMP_WORD ((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |\
|
||||
(TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)
|
||||
|
||||
/**
|
||||
* lro_segment_ok - check if a TCP segment is eligible for LRO
|
||||
* @tcph: the TCP header of the packet
|
||||
*
|
||||
* Returns true if a TCP packet is eligible for LRO. This requires that
|
||||
* the packet have only the ACK flag set and no TCP options besides
|
||||
* time stamps.
|
||||
*/
|
||||
static inline int lro_segment_ok(const struct tcphdr *tcph)
|
||||
{
|
||||
int optlen;
|
||||
|
||||
if (unlikely((tcp_flag_word(tcph) & TCP_FLAG_MASK) != TCP_FLAG_ACK))
|
||||
return 0;
|
||||
|
||||
optlen = (tcph->doff << 2) - sizeof(*tcph);
|
||||
if (optlen) {
|
||||
const u32 *opt = (const u32 *)(tcph + 1);
|
||||
|
||||
if (optlen != TCPOLEN_TSTAMP_ALIGNED ||
|
||||
*opt != htonl(TSTAMP_WORD) || !opt[2])
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int t3_get_lro_header(void **eh, void **iph, void **tcph,
|
||||
u64 *hdr_flags, void *priv)
|
||||
{
|
||||
|
|
@ -1981,9 +1947,6 @@ static int t3_get_lro_header(void **eh, void **iph, void **tcph,
|
|||
*iph = (struct iphdr *)((struct ethhdr *)*eh + 1);
|
||||
*tcph = (struct tcphdr *)((struct iphdr *)*iph + 1);
|
||||
|
||||
if (!lro_segment_ok(*tcph))
|
||||
return -1;
|
||||
|
||||
*hdr_flags = LRO_IPV4 | LRO_TCP;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2878,9 +2841,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
|
|||
struct net_lro_mgr *lro_mgr = &q->lro_mgr;
|
||||
|
||||
init_qset_cntxt(q, id);
|
||||
init_timer(&q->tx_reclaim_timer);
|
||||
q->tx_reclaim_timer.data = (unsigned long)q;
|
||||
q->tx_reclaim_timer.function = sge_timer_cb;
|
||||
setup_timer(&q->tx_reclaim_timer, sge_timer_cb, (unsigned long)q);
|
||||
|
||||
q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size,
|
||||
sizeof(struct rx_desc),
|
||||
|
|
@ -2934,6 +2895,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
|
|||
q->rspq.gen = 1;
|
||||
q->rspq.size = p->rspq_size;
|
||||
spin_lock_init(&q->rspq.lock);
|
||||
skb_queue_head_init(&q->rspq.rx_queue);
|
||||
|
||||
q->txq[TXQ_ETH].stop_thres = nports *
|
||||
flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3);
|
||||
|
|
@ -3042,6 +3004,24 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* t3_stop_sge_timers - stop SGE timer call backs
|
||||
* @adap: the adapter
|
||||
*
|
||||
* Stops each SGE queue set's timer call back
|
||||
*/
|
||||
void t3_stop_sge_timers(struct adapter *adap)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < SGE_QSETS; ++i) {
|
||||
struct sge_qset *q = &adap->sge.qs[i];
|
||||
|
||||
if (q->tx_reclaim_timer.function)
|
||||
del_timer_sync(&q->tx_reclaim_timer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* t3_free_sge_resources - free SGE resources
|
||||
* @adap: the adapter
|
||||
|
|
|
|||
|
|
@ -194,21 +194,18 @@ int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
|
|||
static void mi1_init(struct adapter *adap, const struct adapter_info *ai)
|
||||
{
|
||||
u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1;
|
||||
u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) |
|
||||
V_CLKDIV(clkdiv);
|
||||
u32 val = F_PREEN | V_CLKDIV(clkdiv);
|
||||
|
||||
if (!(ai->caps & SUPPORTED_10000baseT_Full))
|
||||
val |= V_ST(1);
|
||||
t3_write_reg(adap, A_MI1_CFG, val);
|
||||
}
|
||||
|
||||
#define MDIO_ATTEMPTS 10
|
||||
#define MDIO_ATTEMPTS 20
|
||||
|
||||
/*
|
||||
* MI1 read/write operations for direct-addressed PHYs.
|
||||
* MI1 read/write operations for clause 22 PHYs.
|
||||
*/
|
||||
static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr,
|
||||
int reg_addr, unsigned int *valp)
|
||||
static int t3_mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr,
|
||||
int reg_addr, unsigned int *valp)
|
||||
{
|
||||
int ret;
|
||||
u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
|
||||
|
|
@ -217,16 +214,17 @@ static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr,
|
|||
return -EINVAL;
|
||||
|
||||
mutex_lock(&adapter->mdio_lock);
|
||||
t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1));
|
||||
t3_write_reg(adapter, A_MI1_ADDR, addr);
|
||||
t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2));
|
||||
ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
|
||||
ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
|
||||
if (!ret)
|
||||
*valp = t3_read_reg(adapter, A_MI1_DATA);
|
||||
mutex_unlock(&adapter->mdio_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr,
|
||||
static int t3_mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr,
|
||||
int reg_addr, unsigned int val)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -236,19 +234,37 @@ static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr,
|
|||
return -EINVAL;
|
||||
|
||||
mutex_lock(&adapter->mdio_lock);
|
||||
t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1));
|
||||
t3_write_reg(adapter, A_MI1_ADDR, addr);
|
||||
t3_write_reg(adapter, A_MI1_DATA, val);
|
||||
t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
|
||||
ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
|
||||
ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
|
||||
mutex_unlock(&adapter->mdio_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct mdio_ops mi1_mdio_ops = {
|
||||
mi1_read,
|
||||
mi1_write
|
||||
t3_mi1_read,
|
||||
t3_mi1_write
|
||||
};
|
||||
|
||||
/*
|
||||
* Performs the address cycle for clause 45 PHYs.
|
||||
* Must be called with the MDIO_LOCK held.
|
||||
*/
|
||||
static int mi1_wr_addr(struct adapter *adapter, int phy_addr, int mmd_addr,
|
||||
int reg_addr)
|
||||
{
|
||||
u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
|
||||
|
||||
t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), 0);
|
||||
t3_write_reg(adapter, A_MI1_ADDR, addr);
|
||||
t3_write_reg(adapter, A_MI1_DATA, reg_addr);
|
||||
t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
|
||||
return t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
|
||||
MDIO_ATTEMPTS, 10);
|
||||
}
|
||||
|
||||
/*
|
||||
* MI1 read/write operations for indirect-addressed PHYs.
|
||||
*/
|
||||
|
|
@ -256,17 +272,13 @@ static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr,
|
|||
int reg_addr, unsigned int *valp)
|
||||
{
|
||||
int ret;
|
||||
u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
|
||||
|
||||
mutex_lock(&adapter->mdio_lock);
|
||||
t3_write_reg(adapter, A_MI1_ADDR, addr);
|
||||
t3_write_reg(adapter, A_MI1_DATA, reg_addr);
|
||||
t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
|
||||
ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
|
||||
ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr);
|
||||
if (!ret) {
|
||||
t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3));
|
||||
ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
|
||||
MDIO_ATTEMPTS, 20);
|
||||
MDIO_ATTEMPTS, 10);
|
||||
if (!ret)
|
||||
*valp = t3_read_reg(adapter, A_MI1_DATA);
|
||||
}
|
||||
|
|
@ -278,18 +290,14 @@ static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr,
|
|||
int reg_addr, unsigned int val)
|
||||
{
|
||||
int ret;
|
||||
u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
|
||||
|
||||
mutex_lock(&adapter->mdio_lock);
|
||||
t3_write_reg(adapter, A_MI1_ADDR, addr);
|
||||
t3_write_reg(adapter, A_MI1_DATA, reg_addr);
|
||||
t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
|
||||
ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
|
||||
ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr);
|
||||
if (!ret) {
|
||||
t3_write_reg(adapter, A_MI1_DATA, val);
|
||||
t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
|
||||
ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
|
||||
MDIO_ATTEMPTS, 20);
|
||||
MDIO_ATTEMPTS, 10);
|
||||
}
|
||||
mutex_unlock(&adapter->mdio_lock);
|
||||
return ret;
|
||||
|
|
@ -399,6 +407,29 @@ int t3_phy_advertise(struct cphy *phy, unsigned int advert)
|
|||
return mdio_write(phy, 0, MII_ADVERTISE, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* t3_phy_advertise_fiber - set fiber PHY advertisement register
|
||||
* @phy: the PHY to operate on
|
||||
* @advert: bitmap of capabilities the PHY should advertise
|
||||
*
|
||||
* Sets a fiber PHY's advertisement register to advertise the
|
||||
* requested capabilities.
|
||||
*/
|
||||
int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert)
|
||||
{
|
||||
unsigned int val = 0;
|
||||
|
||||
if (advert & ADVERTISED_1000baseT_Half)
|
||||
val |= ADVERTISE_1000XHALF;
|
||||
if (advert & ADVERTISED_1000baseT_Full)
|
||||
val |= ADVERTISE_1000XFULL;
|
||||
if (advert & ADVERTISED_Pause)
|
||||
val |= ADVERTISE_1000XPAUSE;
|
||||
if (advert & ADVERTISED_Asym_Pause)
|
||||
val |= ADVERTISE_1000XPSE_ASYM;
|
||||
return mdio_write(phy, 0, MII_ADVERTISE, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* t3_set_phy_speed_duplex - force PHY speed and duplex
|
||||
* @phy: the PHY to operate on
|
||||
|
|
@ -434,27 +465,52 @@ int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
|
|||
return mdio_write(phy, 0, MII_BMCR, ctl);
|
||||
}
|
||||
|
||||
int t3_phy_lasi_intr_enable(struct cphy *phy)
|
||||
{
|
||||
return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
|
||||
}
|
||||
|
||||
int t3_phy_lasi_intr_disable(struct cphy *phy)
|
||||
{
|
||||
return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
|
||||
}
|
||||
|
||||
int t3_phy_lasi_intr_clear(struct cphy *phy)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
|
||||
}
|
||||
|
||||
int t3_phy_lasi_intr_handler(struct cphy *phy)
|
||||
{
|
||||
unsigned int status;
|
||||
int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
return (status & 1) ? cphy_cause_link_change : 0;
|
||||
}
|
||||
|
||||
static const struct adapter_info t3_adap_info[] = {
|
||||
{2, 0, 0, 0,
|
||||
{2, 0,
|
||||
F_GPIO2_OEN | F_GPIO4_OEN |
|
||||
F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
|
||||
0,
|
||||
F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0,
|
||||
&mi1_mdio_ops, "Chelsio PE9000"},
|
||||
{2, 0, 0, 0,
|
||||
{2, 0,
|
||||
F_GPIO2_OEN | F_GPIO4_OEN |
|
||||
F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
|
||||
0,
|
||||
F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0,
|
||||
&mi1_mdio_ops, "Chelsio T302"},
|
||||
{1, 0, 0, 0,
|
||||
{1, 0,
|
||||
F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
|
||||
F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
|
||||
0, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
|
||||
{ 0 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
|
||||
&mi1_mdio_ext_ops, "Chelsio T310"},
|
||||
{2, 0, 0, 0,
|
||||
{2, 0,
|
||||
F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
|
||||
F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
|
||||
F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
|
||||
SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
|
||||
F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
|
||||
{ S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
|
||||
&mi1_mdio_ext_ops, "Chelsio T320"},
|
||||
};
|
||||
|
||||
|
|
@ -467,28 +523,22 @@ const struct adapter_info *t3_get_adapter_info(unsigned int id)
|
|||
return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL;
|
||||
}
|
||||
|
||||
#define CAPS_1G (SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | \
|
||||
SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII)
|
||||
#define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI)
|
||||
|
||||
static const struct port_type_info port_types[] = {
|
||||
{NULL},
|
||||
{t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
|
||||
"10GBASE-XR"},
|
||||
{t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
|
||||
"10/100/1000BASE-T"},
|
||||
{NULL, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
|
||||
"10/100/1000BASE-T"},
|
||||
{t3_xaui_direct_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
|
||||
{NULL, CAPS_10G, "10GBASE-KX4"},
|
||||
{t3_qt2045_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
|
||||
{t3_ael1006_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
|
||||
"10GBASE-SR"},
|
||||
{NULL, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
|
||||
struct port_type_info {
|
||||
int (*phy_prep)(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *ops);
|
||||
};
|
||||
|
||||
#undef CAPS_1G
|
||||
#undef CAPS_10G
|
||||
static const struct port_type_info port_types[] = {
|
||||
{ NULL },
|
||||
{ t3_ael1002_phy_prep },
|
||||
{ t3_vsc8211_phy_prep },
|
||||
{ NULL},
|
||||
{ t3_xaui_direct_phy_prep },
|
||||
{ t3_ael2005_phy_prep },
|
||||
{ t3_qt2045_phy_prep },
|
||||
{ t3_ael1006_phy_prep },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
#define VPD_ENTRY(name, len) \
|
||||
u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
|
||||
|
|
@ -1132,6 +1182,15 @@ void t3_link_changed(struct adapter *adapter, int port_id)
|
|||
|
||||
phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
|
||||
|
||||
if (lc->requested_fc & PAUSE_AUTONEG)
|
||||
fc &= lc->requested_fc;
|
||||
else
|
||||
fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
|
||||
|
||||
if (link_ok == lc->link_ok && speed == lc->speed &&
|
||||
duplex == lc->duplex && fc == lc->fc)
|
||||
return; /* nothing changed */
|
||||
|
||||
if (link_ok != lc->link_ok && adapter->params.rev > 0 &&
|
||||
uses_xaui(adapter)) {
|
||||
if (link_ok)
|
||||
|
|
@ -1142,10 +1201,6 @@ void t3_link_changed(struct adapter *adapter, int port_id)
|
|||
lc->link_ok = link_ok;
|
||||
lc->speed = speed < 0 ? SPEED_INVALID : speed;
|
||||
lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
|
||||
if (lc->requested_fc & PAUSE_AUTONEG)
|
||||
fc &= lc->requested_fc;
|
||||
else
|
||||
fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
|
||||
|
||||
if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
|
||||
/* Set MAC speed, duplex, and flow control to match PHY. */
|
||||
|
|
@ -1191,7 +1246,6 @@ int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
|
|||
fc);
|
||||
/* Also disables autoneg */
|
||||
phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
|
||||
phy->ops->reset(phy, 0);
|
||||
} else
|
||||
phy->ops->autoneg_enable(phy);
|
||||
} else {
|
||||
|
|
@ -1221,7 +1275,7 @@ struct intr_info {
|
|||
unsigned int mask; /* bits to check in interrupt status */
|
||||
const char *msg; /* message to print or NULL */
|
||||
short stat_idx; /* stat counter to increment or -1 */
|
||||
unsigned short fatal:1; /* whether the condition reported is fatal */
|
||||
unsigned short fatal; /* whether the condition reported is fatal */
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -1682,25 +1736,23 @@ static int mac_intr_handler(struct adapter *adap, unsigned int idx)
|
|||
*/
|
||||
int t3_phy_intr_handler(struct adapter *adapter)
|
||||
{
|
||||
u32 mask, gpi = adapter_info(adapter)->gpio_intr;
|
||||
u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
|
||||
|
||||
for_each_port(adapter, i) {
|
||||
struct port_info *p = adap2pinfo(adapter, i);
|
||||
|
||||
mask = gpi - (gpi & (gpi - 1));
|
||||
gpi -= mask;
|
||||
|
||||
if (!(p->port_type->caps & SUPPORTED_IRQ))
|
||||
if (!(p->phy.caps & SUPPORTED_IRQ))
|
||||
continue;
|
||||
|
||||
if (cause & mask) {
|
||||
if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) {
|
||||
int phy_cause = p->phy.ops->intr_handler(&p->phy);
|
||||
|
||||
if (phy_cause & cphy_cause_link_change)
|
||||
t3_link_changed(adapter, i);
|
||||
if (phy_cause & cphy_cause_fifo_error)
|
||||
p->phy.fifo_errors++;
|
||||
if (phy_cause & cphy_cause_module_change)
|
||||
t3_os_phymod_changed(adapter, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1763,6 +1815,17 @@ int t3_slow_intr_handler(struct adapter *adapter)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static unsigned int calc_gpio_intr(struct adapter *adap)
|
||||
{
|
||||
unsigned int i, gpi_intr = 0;
|
||||
|
||||
for_each_port(adap, i)
|
||||
if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) &&
|
||||
adapter_info(adap)->gpio_intr[i])
|
||||
gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i];
|
||||
return gpi_intr;
|
||||
}
|
||||
|
||||
/**
|
||||
* t3_intr_enable - enable interrupts
|
||||
* @adapter: the adapter whose interrupts should be enabled
|
||||
|
|
@ -1805,10 +1868,8 @@ void t3_intr_enable(struct adapter *adapter)
|
|||
t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
|
||||
}
|
||||
|
||||
t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW,
|
||||
adapter_info(adapter)->gpio_intr);
|
||||
t3_write_reg(adapter, A_T3DBG_INT_ENABLE,
|
||||
adapter_info(adapter)->gpio_intr);
|
||||
t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter));
|
||||
|
||||
if (is_pcie(adapter))
|
||||
t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
|
||||
else
|
||||
|
|
@ -3329,6 +3390,8 @@ int t3_init_hw(struct adapter *adapter, u32 fw_params)
|
|||
init_hw_for_avail_ports(adapter, adapter->params.nports);
|
||||
t3_sge_init(adapter, &adapter->params.sge);
|
||||
|
||||
t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter));
|
||||
|
||||
t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
|
||||
t3_write_reg(adapter, A_CIM_BOOT_CFG,
|
||||
V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
|
||||
|
|
@ -3488,7 +3551,7 @@ void early_hw_init(struct adapter *adapter, const struct adapter_info *ai)
|
|||
* Older PCIe cards lose their config space during reset, PCI-X
|
||||
* ones don't.
|
||||
*/
|
||||
static int t3_reset_adapter(struct adapter *adapter)
|
||||
int t3_reset_adapter(struct adapter *adapter)
|
||||
{
|
||||
int i, save_and_restore_pcie =
|
||||
adapter->params.rev < T3_REV_B2 && is_pcie(adapter);
|
||||
|
|
@ -3556,7 +3619,7 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
|
|||
int reset)
|
||||
{
|
||||
int ret;
|
||||
unsigned int i, j = 0;
|
||||
unsigned int i, j = -1;
|
||||
|
||||
get_pci_mode(adapter, &adapter->params.pci);
|
||||
|
||||
|
|
@ -3620,16 +3683,18 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
|
|||
|
||||
for_each_port(adapter, i) {
|
||||
u8 hw_addr[6];
|
||||
const struct port_type_info *pti;
|
||||
struct port_info *p = adap2pinfo(adapter, i);
|
||||
|
||||
while (!adapter->params.vpd.port_type[j])
|
||||
++j;
|
||||
while (!adapter->params.vpd.port_type[++j])
|
||||
;
|
||||
|
||||
p->port_type = &port_types[adapter->params.vpd.port_type[j]];
|
||||
p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
|
||||
ai->mdio_ops);
|
||||
pti = &port_types[adapter->params.vpd.port_type[j]];
|
||||
ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
|
||||
ai->mdio_ops);
|
||||
if (ret)
|
||||
return ret;
|
||||
mac_prep(&p->mac, adapter, j);
|
||||
++j;
|
||||
|
||||
/*
|
||||
* The VPD EEPROM stores the base Ethernet address for the
|
||||
|
|
@ -3643,9 +3708,9 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
|
|||
ETH_ALEN);
|
||||
memcpy(adapter->port[i]->perm_addr, hw_addr,
|
||||
ETH_ALEN);
|
||||
init_link_config(&p->link_config, p->port_type->caps);
|
||||
init_link_config(&p->link_config, p->phy.caps);
|
||||
p->phy.ops->power_down(&p->phy, 1);
|
||||
if (!(p->port_type->caps & SUPPORTED_IRQ))
|
||||
if (!(p->phy.caps & SUPPORTED_IRQ))
|
||||
adapter->params.linkpoll_period = 10;
|
||||
}
|
||||
|
||||
|
|
@ -3661,7 +3726,7 @@ void t3_led_ready(struct adapter *adapter)
|
|||
int t3_replay_prep_adapter(struct adapter *adapter)
|
||||
{
|
||||
const struct adapter_info *ai = adapter->params.info;
|
||||
unsigned int i, j = 0;
|
||||
unsigned int i, j = -1;
|
||||
int ret;
|
||||
|
||||
early_hw_init(adapter, ai);
|
||||
|
|
@ -3670,15 +3735,17 @@ int t3_replay_prep_adapter(struct adapter *adapter)
|
|||
return ret;
|
||||
|
||||
for_each_port(adapter, i) {
|
||||
const struct port_type_info *pti;
|
||||
struct port_info *p = adap2pinfo(adapter, i);
|
||||
while (!adapter->params.vpd.port_type[j])
|
||||
++j;
|
||||
|
||||
p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
|
||||
ai->mdio_ops);
|
||||
while (!adapter->params.vpd.port_type[++j])
|
||||
;
|
||||
|
||||
pti = &port_types[adapter->params.vpd.port_type[j]];
|
||||
ret = pti->phy_prep(&p->phy, adapter, p->phy.addr, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
p->phy.ops->power_down(&p->phy, 1);
|
||||
++j;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -33,28 +33,40 @@
|
|||
|
||||
/* VSC8211 PHY specific registers. */
|
||||
enum {
|
||||
VSC8211_SIGDET_CTRL = 19,
|
||||
VSC8211_EXT_CTRL = 23,
|
||||
VSC8211_INTR_ENABLE = 25,
|
||||
VSC8211_INTR_STATUS = 26,
|
||||
VSC8211_LED_CTRL = 27,
|
||||
VSC8211_AUX_CTRL_STAT = 28,
|
||||
VSC8211_EXT_PAGE_AXS = 31,
|
||||
};
|
||||
|
||||
enum {
|
||||
VSC_INTR_RX_ERR = 1 << 0,
|
||||
VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */
|
||||
VSC_INTR_CABLE = 1 << 2, /* cable impairment */
|
||||
VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */
|
||||
VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */
|
||||
VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */
|
||||
VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */
|
||||
VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */
|
||||
VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */
|
||||
VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
|
||||
VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
|
||||
VSC_INTR_LINK_CHG = 1 << 13, /* link change */
|
||||
VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
|
||||
VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */
|
||||
VSC_INTR_CABLE = 1 << 2, /* cable impairment */
|
||||
VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */
|
||||
VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */
|
||||
VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */
|
||||
VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */
|
||||
VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */
|
||||
VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */
|
||||
VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */
|
||||
VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */
|
||||
VSC_INTR_DPLX_CHG = 1 << 12, /* duplex change */
|
||||
VSC_INTR_LINK_CHG = 1 << 13, /* link change */
|
||||
VSC_INTR_SPD_CHG = 1 << 14, /* speed change */
|
||||
VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */
|
||||
};
|
||||
|
||||
enum {
|
||||
VSC_CTRL_CLAUSE37_VIEW = 1 << 4, /* Switch to Clause 37 view */
|
||||
VSC_CTRL_MEDIA_MODE_HI = 0xf000 /* High part of media mode select */
|
||||
};
|
||||
|
||||
#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
|
||||
VSC_INTR_DPLX_CHG | VSC_INTR_SPD_CHG | \
|
||||
VSC_INTR_NEG_DONE)
|
||||
#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
|
||||
VSC_INTR_ENABLE)
|
||||
|
|
@ -184,6 +196,112 @@ static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok,
|
||||
int *speed, int *duplex, int *fc)
|
||||
{
|
||||
unsigned int bmcr, status, lpa, adv;
|
||||
int err, sp = -1, dplx = -1, pause = 0;
|
||||
|
||||
err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
|
||||
if (!err)
|
||||
err = mdio_read(cphy, 0, MII_BMSR, &status);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (link_ok) {
|
||||
/*
|
||||
* BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
|
||||
* once more to get the current link state.
|
||||
*/
|
||||
if (!(status & BMSR_LSTATUS))
|
||||
err = mdio_read(cphy, 0, MII_BMSR, &status);
|
||||
if (err)
|
||||
return err;
|
||||
*link_ok = (status & BMSR_LSTATUS) != 0;
|
||||
}
|
||||
if (!(bmcr & BMCR_ANENABLE)) {
|
||||
dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
|
||||
if (bmcr & BMCR_SPEED1000)
|
||||
sp = SPEED_1000;
|
||||
else if (bmcr & BMCR_SPEED100)
|
||||
sp = SPEED_100;
|
||||
else
|
||||
sp = SPEED_10;
|
||||
} else if (status & BMSR_ANEGCOMPLETE) {
|
||||
err = mdio_read(cphy, 0, MII_LPA, &lpa);
|
||||
if (!err)
|
||||
err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (adv & lpa & ADVERTISE_1000XFULL) {
|
||||
dplx = DUPLEX_FULL;
|
||||
sp = SPEED_1000;
|
||||
} else if (adv & lpa & ADVERTISE_1000XHALF) {
|
||||
dplx = DUPLEX_HALF;
|
||||
sp = SPEED_1000;
|
||||
}
|
||||
|
||||
if (fc && dplx == DUPLEX_FULL) {
|
||||
if (lpa & adv & ADVERTISE_1000XPAUSE)
|
||||
pause = PAUSE_RX | PAUSE_TX;
|
||||
else if ((lpa & ADVERTISE_1000XPAUSE) &&
|
||||
(adv & lpa & ADVERTISE_1000XPSE_ASYM))
|
||||
pause = PAUSE_TX;
|
||||
else if ((lpa & ADVERTISE_1000XPSE_ASYM) &&
|
||||
(adv & ADVERTISE_1000XPAUSE))
|
||||
pause = PAUSE_RX;
|
||||
}
|
||||
}
|
||||
if (speed)
|
||||
*speed = sp;
|
||||
if (duplex)
|
||||
*duplex = dplx;
|
||||
if (fc)
|
||||
*fc = pause;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable/disable auto MDI/MDI-X in forced link speed mode.
|
||||
*/
|
||||
static int vsc8211_set_automdi(struct cphy *phy, int enable)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0x52b5);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mdio_write(phy, 0, 18, 0x12);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mdio_write(phy, 0, 17, enable ? 0x2803 : 0x3003);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mdio_write(phy, 0, 16, 0x87fa);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = t3_set_phy_speed_duplex(phy, speed, duplex);
|
||||
if (!err)
|
||||
err = vsc8211_set_automdi(phy, 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vsc8211_power_down(struct cphy *cphy, int enable)
|
||||
{
|
||||
return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
|
||||
|
|
@ -221,8 +339,66 @@ static struct cphy_ops vsc8211_ops = {
|
|||
.power_down = vsc8211_power_down,
|
||||
};
|
||||
|
||||
void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *mdio_ops)
|
||||
static struct cphy_ops vsc8211_fiber_ops = {
|
||||
.reset = vsc8211_reset,
|
||||
.intr_enable = vsc8211_intr_enable,
|
||||
.intr_disable = vsc8211_intr_disable,
|
||||
.intr_clear = vsc8211_intr_clear,
|
||||
.intr_handler = vsc8211_intr_handler,
|
||||
.autoneg_enable = vsc8211_autoneg_enable,
|
||||
.autoneg_restart = vsc8211_autoneg_restart,
|
||||
.advertise = t3_phy_advertise_fiber,
|
||||
.set_speed_duplex = t3_set_phy_speed_duplex,
|
||||
.get_link_status = vsc8211_get_link_status_fiber,
|
||||
.power_down = vsc8211_power_down,
|
||||
};
|
||||
|
||||
int t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
|
||||
int phy_addr, const struct mdio_ops *mdio_ops)
|
||||
{
|
||||
cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops);
|
||||
int err;
|
||||
unsigned int val;
|
||||
|
||||
cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops,
|
||||
SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full |
|
||||
SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII |
|
||||
SUPPORTED_TP | SUPPORTED_IRQ, "10/100/1000BASE-T");
|
||||
msleep(20); /* PHY needs ~10ms to start responding to MDIO */
|
||||
|
||||
err = mdio_read(phy, 0, VSC8211_EXT_CTRL, &val);
|
||||
if (err)
|
||||
return err;
|
||||
if (val & VSC_CTRL_MEDIA_MODE_HI) {
|
||||
/* copper interface, just need to configure the LEDs */
|
||||
return mdio_write(phy, 0, VSC8211_LED_CTRL, 0x100);
|
||||
}
|
||||
|
||||
phy->caps = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
|
||||
SUPPORTED_MII | SUPPORTED_FIBRE | SUPPORTED_IRQ;
|
||||
phy->desc = "1000BASE-X";
|
||||
phy->ops = &vsc8211_fiber_ops;
|
||||
|
||||
err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mdio_write(phy, 0, VSC8211_SIGDET_CTRL, 1);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mdio_write(phy, 0, VSC8211_EXT_PAGE_AXS, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = mdio_write(phy, 0, VSC8211_EXT_CTRL,
|
||||
val | VSC_CTRL_CLAUSE37_VIEW);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = vsc8211_reset(phy, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
udelay(5); /* delay after reset before next SMI */
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ MODULE_PARM_DESC(use_io, "Force use of i/o access mode");
|
|||
#define DPRINTK(nlevel, klevel, fmt, args...) \
|
||||
(void)((NETIF_MSG_##nlevel & nic->msg_enable) && \
|
||||
printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \
|
||||
__FUNCTION__ , ## args))
|
||||
__func__ , ## args))
|
||||
|
||||
#define INTEL_8255X_ETHERNET_DEVICE(device_id, ich) {\
|
||||
PCI_VENDOR_ID_INTEL, device_id, PCI_ANY_ID, PCI_ANY_ID, \
|
||||
|
|
@ -2738,9 +2738,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
|
|||
nic->flags |= wol_magic;
|
||||
|
||||
/* ack any pending wake events, disable PME */
|
||||
err = pci_enable_wake(pdev, 0, 0);
|
||||
if (err)
|
||||
DPRINTK(PROBE, ERR, "Error clearing wake event\n");
|
||||
pci_pme_active(pdev, false);
|
||||
|
||||
strcpy(netdev->name, "eth%d");
|
||||
if((err = register_netdev(netdev))) {
|
||||
|
|
|
|||
|
|
@ -155,8 +155,6 @@ do { \
|
|||
#endif
|
||||
|
||||
#define E1000_MNG_VLAN_NONE (-1)
|
||||
/* Number of packet split data buffers (not including the header buffer) */
|
||||
#define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1)
|
||||
|
||||
/* wrapper around a pointer to a socket buffer,
|
||||
* so a DMA handle can be stored along with the buffer */
|
||||
|
|
@ -168,14 +166,6 @@ struct e1000_buffer {
|
|||
u16 next_to_watch;
|
||||
};
|
||||
|
||||
struct e1000_ps_page {
|
||||
struct page *ps_page[PS_PAGE_BUFFERS];
|
||||
};
|
||||
|
||||
struct e1000_ps_page_dma {
|
||||
u64 ps_page_dma[PS_PAGE_BUFFERS];
|
||||
};
|
||||
|
||||
struct e1000_tx_ring {
|
||||
/* pointer to the descriptor ring memory */
|
||||
void *desc;
|
||||
|
|
@ -213,9 +203,6 @@ struct e1000_rx_ring {
|
|||
unsigned int next_to_clean;
|
||||
/* array of buffer information structs */
|
||||
struct e1000_buffer *buffer_info;
|
||||
/* arrays of page information for packet split */
|
||||
struct e1000_ps_page *ps_page;
|
||||
struct e1000_ps_page_dma *ps_page_dma;
|
||||
|
||||
/* cpu for rx queue */
|
||||
int cpu;
|
||||
|
|
@ -228,8 +215,6 @@ struct e1000_rx_ring {
|
|||
((((R)->next_to_clean > (R)->next_to_use) \
|
||||
? 0 : (R)->count) + (R)->next_to_clean - (R)->next_to_use - 1)
|
||||
|
||||
#define E1000_RX_DESC_PS(R, i) \
|
||||
(&(((union e1000_rx_desc_packet_split *)((R).desc))[i]))
|
||||
#define E1000_RX_DESC_EXT(R, i) \
|
||||
(&(((union e1000_rx_desc_extended *)((R).desc))[i]))
|
||||
#define E1000_GET_DESC(R, i, type) (&(((struct type *)((R).desc))[i]))
|
||||
|
|
@ -311,10 +296,8 @@ struct e1000_adapter {
|
|||
u32 rx_int_delay;
|
||||
u32 rx_abs_int_delay;
|
||||
bool rx_csum;
|
||||
unsigned int rx_ps_pages;
|
||||
u32 gorcl;
|
||||
u64 gorcl_old;
|
||||
u16 rx_ps_bsize0;
|
||||
|
||||
/* OS defined structs */
|
||||
struct net_device *netdev;
|
||||
|
|
|
|||
|
|
@ -144,6 +144,8 @@ static s32 e1000_host_if_read_cookie(struct e1000_hw *hw, u8 *buffer);
|
|||
static u8 e1000_calculate_mng_checksum(char *buffer, u32 length);
|
||||
static s32 e1000_configure_kmrn_for_10_100(struct e1000_hw *hw, u16 duplex);
|
||||
static s32 e1000_configure_kmrn_for_1000(struct e1000_hw *hw);
|
||||
static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
|
||||
static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data);
|
||||
|
||||
/* IGP cable length table */
|
||||
static const
|
||||
|
|
@ -168,6 +170,8 @@ u16 e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] =
|
|||
83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
|
||||
104, 109, 114, 118, 121, 124};
|
||||
|
||||
static DEFINE_SPINLOCK(e1000_eeprom_lock);
|
||||
|
||||
/******************************************************************************
|
||||
* Set the phy type member in the hw struct.
|
||||
*
|
||||
|
|
@ -4903,6 +4907,15 @@ static s32 e1000_spi_eeprom_ready(struct e1000_hw *hw)
|
|||
* words - number of words to read
|
||||
*****************************************************************************/
|
||||
s32 e1000_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
|
||||
{
|
||||
s32 ret;
|
||||
spin_lock(&e1000_eeprom_lock);
|
||||
ret = e1000_do_read_eeprom(hw, offset, words, data);
|
||||
spin_unlock(&e1000_eeprom_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
|
||||
{
|
||||
struct e1000_eeprom_info *eeprom = &hw->eeprom;
|
||||
u32 i = 0;
|
||||
|
|
@ -5235,6 +5248,16 @@ s32 e1000_update_eeprom_checksum(struct e1000_hw *hw)
|
|||
* EEPROM will most likely contain an invalid checksum.
|
||||
*****************************************************************************/
|
||||
s32 e1000_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
|
||||
{
|
||||
s32 ret;
|
||||
spin_lock(&e1000_eeprom_lock);
|
||||
ret = e1000_do_write_eeprom(hw, offset, words, data);
|
||||
spin_unlock(&e1000_eeprom_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
|
||||
{
|
||||
struct e1000_eeprom_info *eeprom = &hw->eeprom;
|
||||
s32 status = 0;
|
||||
|
|
|
|||
|
|
@ -137,15 +137,9 @@ static int e1000_clean(struct napi_struct *napi, int budget);
|
|||
static bool e1000_clean_rx_irq(struct e1000_adapter *adapter,
|
||||
struct e1000_rx_ring *rx_ring,
|
||||
int *work_done, int work_to_do);
|
||||
static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
|
||||
struct e1000_rx_ring *rx_ring,
|
||||
int *work_done, int work_to_do);
|
||||
static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter,
|
||||
struct e1000_rx_ring *rx_ring,
|
||||
int cleaned_count);
|
||||
static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
|
||||
struct e1000_rx_ring *rx_ring,
|
||||
int cleaned_count);
|
||||
static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
|
||||
static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
|
||||
int cmd);
|
||||
|
|
@ -1331,7 +1325,6 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
|
|||
pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
|
||||
|
||||
adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE;
|
||||
adapter->rx_ps_bsize0 = E1000_RXBUFFER_128;
|
||||
hw->max_frame_size = netdev->mtu +
|
||||
ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
|
||||
hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
|
||||
|
|
@ -1815,26 +1808,6 @@ static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
|
|||
}
|
||||
memset(rxdr->buffer_info, 0, size);
|
||||
|
||||
rxdr->ps_page = kcalloc(rxdr->count, sizeof(struct e1000_ps_page),
|
||||
GFP_KERNEL);
|
||||
if (!rxdr->ps_page) {
|
||||
vfree(rxdr->buffer_info);
|
||||
DPRINTK(PROBE, ERR,
|
||||
"Unable to allocate memory for the receive descriptor ring\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rxdr->ps_page_dma = kcalloc(rxdr->count,
|
||||
sizeof(struct e1000_ps_page_dma),
|
||||
GFP_KERNEL);
|
||||
if (!rxdr->ps_page_dma) {
|
||||
vfree(rxdr->buffer_info);
|
||||
kfree(rxdr->ps_page);
|
||||
DPRINTK(PROBE, ERR,
|
||||
"Unable to allocate memory for the receive descriptor ring\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (hw->mac_type <= e1000_82547_rev_2)
|
||||
desc_len = sizeof(struct e1000_rx_desc);
|
||||
else
|
||||
|
|
@ -1852,8 +1825,6 @@ static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
|
|||
"Unable to allocate memory for the receive descriptor ring\n");
|
||||
setup_rx_desc_die:
|
||||
vfree(rxdr->buffer_info);
|
||||
kfree(rxdr->ps_page);
|
||||
kfree(rxdr->ps_page_dma);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -1932,11 +1903,7 @@ int e1000_setup_all_rx_resources(struct e1000_adapter *adapter)
|
|||
static void e1000_setup_rctl(struct e1000_adapter *adapter)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
u32 rctl, rfctl;
|
||||
u32 psrctl = 0;
|
||||
#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT
|
||||
u32 pages = 0;
|
||||
#endif
|
||||
u32 rctl;
|
||||
|
||||
rctl = er32(RCTL);
|
||||
|
||||
|
|
@ -1988,55 +1955,6 @@ static void e1000_setup_rctl(struct e1000_adapter *adapter)
|
|||
break;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_E1000_DISABLE_PACKET_SPLIT
|
||||
/* 82571 and greater support packet-split where the protocol
|
||||
* header is placed in skb->data and the packet data is
|
||||
* placed in pages hanging off of skb_shinfo(skb)->nr_frags.
|
||||
* In the case of a non-split, skb->data is linearly filled,
|
||||
* followed by the page buffers. Therefore, skb->data is
|
||||
* sized to hold the largest protocol header.
|
||||
*/
|
||||
/* allocations using alloc_page take too long for regular MTU
|
||||
* so only enable packet split for jumbo frames */
|
||||
pages = PAGE_USE_COUNT(adapter->netdev->mtu);
|
||||
if ((hw->mac_type >= e1000_82571) && (pages <= 3) &&
|
||||
PAGE_SIZE <= 16384 && (rctl & E1000_RCTL_LPE))
|
||||
adapter->rx_ps_pages = pages;
|
||||
else
|
||||
adapter->rx_ps_pages = 0;
|
||||
#endif
|
||||
if (adapter->rx_ps_pages) {
|
||||
/* Configure extra packet-split registers */
|
||||
rfctl = er32(RFCTL);
|
||||
rfctl |= E1000_RFCTL_EXTEN;
|
||||
/* disable packet split support for IPv6 extension headers,
|
||||
* because some malformed IPv6 headers can hang the RX */
|
||||
rfctl |= (E1000_RFCTL_IPV6_EX_DIS |
|
||||
E1000_RFCTL_NEW_IPV6_EXT_DIS);
|
||||
|
||||
ew32(RFCTL, rfctl);
|
||||
|
||||
rctl |= E1000_RCTL_DTYP_PS;
|
||||
|
||||
psrctl |= adapter->rx_ps_bsize0 >>
|
||||
E1000_PSRCTL_BSIZE0_SHIFT;
|
||||
|
||||
switch (adapter->rx_ps_pages) {
|
||||
case 3:
|
||||
psrctl |= PAGE_SIZE <<
|
||||
E1000_PSRCTL_BSIZE3_SHIFT;
|
||||
case 2:
|
||||
psrctl |= PAGE_SIZE <<
|
||||
E1000_PSRCTL_BSIZE2_SHIFT;
|
||||
case 1:
|
||||
psrctl |= PAGE_SIZE >>
|
||||
E1000_PSRCTL_BSIZE1_SHIFT;
|
||||
break;
|
||||
}
|
||||
|
||||
ew32(PSRCTL, psrctl);
|
||||
}
|
||||
|
||||
ew32(RCTL, rctl);
|
||||
}
|
||||
|
||||
|
|
@ -2053,18 +1971,10 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
|
|||
struct e1000_hw *hw = &adapter->hw;
|
||||
u32 rdlen, rctl, rxcsum, ctrl_ext;
|
||||
|
||||
if (adapter->rx_ps_pages) {
|
||||
/* this is a 32 byte descriptor */
|
||||
rdlen = adapter->rx_ring[0].count *
|
||||
sizeof(union e1000_rx_desc_packet_split);
|
||||
adapter->clean_rx = e1000_clean_rx_irq_ps;
|
||||
adapter->alloc_rx_buf = e1000_alloc_rx_buffers_ps;
|
||||
} else {
|
||||
rdlen = adapter->rx_ring[0].count *
|
||||
sizeof(struct e1000_rx_desc);
|
||||
adapter->clean_rx = e1000_clean_rx_irq;
|
||||
adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
|
||||
}
|
||||
rdlen = adapter->rx_ring[0].count *
|
||||
sizeof(struct e1000_rx_desc);
|
||||
adapter->clean_rx = e1000_clean_rx_irq;
|
||||
adapter->alloc_rx_buf = e1000_alloc_rx_buffers;
|
||||
|
||||
/* disable receives while setting up the descriptors */
|
||||
rctl = er32(RCTL);
|
||||
|
|
@ -2109,28 +2019,14 @@ static void e1000_configure_rx(struct e1000_adapter *adapter)
|
|||
/* Enable 82543 Receive Checksum Offload for TCP and UDP */
|
||||
if (hw->mac_type >= e1000_82543) {
|
||||
rxcsum = er32(RXCSUM);
|
||||
if (adapter->rx_csum) {
|
||||
if (adapter->rx_csum)
|
||||
rxcsum |= E1000_RXCSUM_TUOFL;
|
||||
|
||||
/* Enable 82571 IPv4 payload checksum for UDP fragments
|
||||
* Must be used in conjunction with packet-split. */
|
||||
if ((hw->mac_type >= e1000_82571) &&
|
||||
(adapter->rx_ps_pages)) {
|
||||
rxcsum |= E1000_RXCSUM_IPPCSE;
|
||||
}
|
||||
} else {
|
||||
rxcsum &= ~E1000_RXCSUM_TUOFL;
|
||||
else
|
||||
/* don't need to clear IPPCSE as it defaults to 0 */
|
||||
}
|
||||
rxcsum &= ~E1000_RXCSUM_TUOFL;
|
||||
ew32(RXCSUM, rxcsum);
|
||||
}
|
||||
|
||||
/* enable early receives on 82573, only takes effect if using > 2048
|
||||
* byte total frame size. for example only for jumbo frames */
|
||||
#define E1000_ERT_2048 0x100
|
||||
if (hw->mac_type == e1000_82573)
|
||||
ew32(ERT, E1000_ERT_2048);
|
||||
|
||||
/* Enable Receives */
|
||||
ew32(RCTL, rctl);
|
||||
}
|
||||
|
|
@ -2256,10 +2152,6 @@ static void e1000_free_rx_resources(struct e1000_adapter *adapter,
|
|||
|
||||
vfree(rx_ring->buffer_info);
|
||||
rx_ring->buffer_info = NULL;
|
||||
kfree(rx_ring->ps_page);
|
||||
rx_ring->ps_page = NULL;
|
||||
kfree(rx_ring->ps_page_dma);
|
||||
rx_ring->ps_page_dma = NULL;
|
||||
|
||||
pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma);
|
||||
|
||||
|
|
@ -2292,11 +2184,9 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
|
|||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct e1000_buffer *buffer_info;
|
||||
struct e1000_ps_page *ps_page;
|
||||
struct e1000_ps_page_dma *ps_page_dma;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
unsigned long size;
|
||||
unsigned int i, j;
|
||||
unsigned int i;
|
||||
|
||||
/* Free all the Rx ring sk_buffs */
|
||||
for (i = 0; i < rx_ring->count; i++) {
|
||||
|
|
@ -2310,25 +2200,10 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter,
|
|||
dev_kfree_skb(buffer_info->skb);
|
||||
buffer_info->skb = NULL;
|
||||
}
|
||||
ps_page = &rx_ring->ps_page[i];
|
||||
ps_page_dma = &rx_ring->ps_page_dma[i];
|
||||
for (j = 0; j < adapter->rx_ps_pages; j++) {
|
||||
if (!ps_page->ps_page[j]) break;
|
||||
pci_unmap_page(pdev,
|
||||
ps_page_dma->ps_page_dma[j],
|
||||
PAGE_SIZE, PCI_DMA_FROMDEVICE);
|
||||
ps_page_dma->ps_page_dma[j] = 0;
|
||||
put_page(ps_page->ps_page[j]);
|
||||
ps_page->ps_page[j] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size = sizeof(struct e1000_buffer) * rx_ring->count;
|
||||
memset(rx_ring->buffer_info, 0, size);
|
||||
size = sizeof(struct e1000_ps_page) * rx_ring->count;
|
||||
memset(rx_ring->ps_page, 0, size);
|
||||
size = sizeof(struct e1000_ps_page_dma) * rx_ring->count;
|
||||
memset(rx_ring->ps_page_dma, 0, size);
|
||||
|
||||
/* Zero out the descriptor ring */
|
||||
|
||||
|
|
@ -2998,32 +2873,49 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter,
|
|||
struct e1000_buffer *buffer_info;
|
||||
unsigned int i;
|
||||
u8 css;
|
||||
u32 cmd_len = E1000_TXD_CMD_DEXT;
|
||||
|
||||
if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
|
||||
css = skb_transport_offset(skb);
|
||||
if (skb->ip_summed != CHECKSUM_PARTIAL)
|
||||
return false;
|
||||
|
||||
i = tx_ring->next_to_use;
|
||||
buffer_info = &tx_ring->buffer_info[i];
|
||||
context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
|
||||
|
||||
context_desc->lower_setup.ip_config = 0;
|
||||
context_desc->upper_setup.tcp_fields.tucss = css;
|
||||
context_desc->upper_setup.tcp_fields.tucso =
|
||||
css + skb->csum_offset;
|
||||
context_desc->upper_setup.tcp_fields.tucse = 0;
|
||||
context_desc->tcp_seg_setup.data = 0;
|
||||
context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
|
||||
|
||||
buffer_info->time_stamp = jiffies;
|
||||
buffer_info->next_to_watch = i;
|
||||
|
||||
if (unlikely(++i == tx_ring->count)) i = 0;
|
||||
tx_ring->next_to_use = i;
|
||||
|
||||
return true;
|
||||
switch (skb->protocol) {
|
||||
case __constant_htons(ETH_P_IP):
|
||||
if (ip_hdr(skb)->protocol == IPPROTO_TCP)
|
||||
cmd_len |= E1000_TXD_CMD_TCP;
|
||||
break;
|
||||
case __constant_htons(ETH_P_IPV6):
|
||||
/* XXX not handling all IPV6 headers */
|
||||
if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
|
||||
cmd_len |= E1000_TXD_CMD_TCP;
|
||||
break;
|
||||
default:
|
||||
if (unlikely(net_ratelimit()))
|
||||
DPRINTK(DRV, WARNING,
|
||||
"checksum_partial proto=%x!\n", skb->protocol);
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
css = skb_transport_offset(skb);
|
||||
|
||||
i = tx_ring->next_to_use;
|
||||
buffer_info = &tx_ring->buffer_info[i];
|
||||
context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
|
||||
|
||||
context_desc->lower_setup.ip_config = 0;
|
||||
context_desc->upper_setup.tcp_fields.tucss = css;
|
||||
context_desc->upper_setup.tcp_fields.tucso =
|
||||
css + skb->csum_offset;
|
||||
context_desc->upper_setup.tcp_fields.tucse = 0;
|
||||
context_desc->tcp_seg_setup.data = 0;
|
||||
context_desc->cmd_and_length = cpu_to_le32(cmd_len);
|
||||
|
||||
buffer_info->time_stamp = jiffies;
|
||||
buffer_info->next_to_watch = i;
|
||||
|
||||
if (unlikely(++i == tx_ring->count)) i = 0;
|
||||
tx_ring->next_to_use = i;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define E1000_MAX_TXD_PWR 12
|
||||
|
|
@ -4234,181 +4126,6 @@ next_desc:
|
|||
return cleaned;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_clean_rx_irq_ps - Send received data up the network stack; packet split
|
||||
* @adapter: board private structure
|
||||
**/
|
||||
|
||||
static bool e1000_clean_rx_irq_ps(struct e1000_adapter *adapter,
|
||||
struct e1000_rx_ring *rx_ring,
|
||||
int *work_done, int work_to_do)
|
||||
{
|
||||
union e1000_rx_desc_packet_split *rx_desc, *next_rxd;
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
struct e1000_buffer *buffer_info, *next_buffer;
|
||||
struct e1000_ps_page *ps_page;
|
||||
struct e1000_ps_page_dma *ps_page_dma;
|
||||
struct sk_buff *skb;
|
||||
unsigned int i, j;
|
||||
u32 length, staterr;
|
||||
int cleaned_count = 0;
|
||||
bool cleaned = false;
|
||||
unsigned int total_rx_bytes=0, total_rx_packets=0;
|
||||
|
||||
i = rx_ring->next_to_clean;
|
||||
rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
|
||||
staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
|
||||
buffer_info = &rx_ring->buffer_info[i];
|
||||
|
||||
while (staterr & E1000_RXD_STAT_DD) {
|
||||
ps_page = &rx_ring->ps_page[i];
|
||||
ps_page_dma = &rx_ring->ps_page_dma[i];
|
||||
|
||||
if (unlikely(*work_done >= work_to_do))
|
||||
break;
|
||||
(*work_done)++;
|
||||
|
||||
skb = buffer_info->skb;
|
||||
|
||||
/* in the packet split case this is header only */
|
||||
prefetch(skb->data - NET_IP_ALIGN);
|
||||
|
||||
if (++i == rx_ring->count) i = 0;
|
||||
next_rxd = E1000_RX_DESC_PS(*rx_ring, i);
|
||||
prefetch(next_rxd);
|
||||
|
||||
next_buffer = &rx_ring->buffer_info[i];
|
||||
|
||||
cleaned = true;
|
||||
cleaned_count++;
|
||||
pci_unmap_single(pdev, buffer_info->dma,
|
||||
buffer_info->length,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
|
||||
if (unlikely(!(staterr & E1000_RXD_STAT_EOP))) {
|
||||
E1000_DBG("%s: Packet Split buffers didn't pick up"
|
||||
" the full packet\n", netdev->name);
|
||||
dev_kfree_skb_irq(skb);
|
||||
goto next_desc;
|
||||
}
|
||||
|
||||
if (unlikely(staterr & E1000_RXDEXT_ERR_FRAME_ERR_MASK)) {
|
||||
dev_kfree_skb_irq(skb);
|
||||
goto next_desc;
|
||||
}
|
||||
|
||||
length = le16_to_cpu(rx_desc->wb.middle.length0);
|
||||
|
||||
if (unlikely(!length)) {
|
||||
E1000_DBG("%s: Last part of the packet spanning"
|
||||
" multiple descriptors\n", netdev->name);
|
||||
dev_kfree_skb_irq(skb);
|
||||
goto next_desc;
|
||||
}
|
||||
|
||||
/* Good Receive */
|
||||
skb_put(skb, length);
|
||||
|
||||
{
|
||||
/* this looks ugly, but it seems compiler issues make it
|
||||
more efficient than reusing j */
|
||||
int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]);
|
||||
|
||||
/* page alloc/put takes too long and effects small packet
|
||||
* throughput, so unsplit small packets and save the alloc/put*/
|
||||
if (l1 && (l1 <= copybreak) && ((length + l1) <= adapter->rx_ps_bsize0)) {
|
||||
u8 *vaddr;
|
||||
/* there is no documentation about how to call
|
||||
* kmap_atomic, so we can't hold the mapping
|
||||
* very long */
|
||||
pci_dma_sync_single_for_cpu(pdev,
|
||||
ps_page_dma->ps_page_dma[0],
|
||||
PAGE_SIZE,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
vaddr = kmap_atomic(ps_page->ps_page[0],
|
||||
KM_SKB_DATA_SOFTIRQ);
|
||||
memcpy(skb_tail_pointer(skb), vaddr, l1);
|
||||
kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ);
|
||||
pci_dma_sync_single_for_device(pdev,
|
||||
ps_page_dma->ps_page_dma[0],
|
||||
PAGE_SIZE, PCI_DMA_FROMDEVICE);
|
||||
/* remove the CRC */
|
||||
l1 -= 4;
|
||||
skb_put(skb, l1);
|
||||
goto copydone;
|
||||
} /* if */
|
||||
}
|
||||
|
||||
for (j = 0; j < adapter->rx_ps_pages; j++) {
|
||||
length = le16_to_cpu(rx_desc->wb.upper.length[j]);
|
||||
if (!length)
|
||||
break;
|
||||
pci_unmap_page(pdev, ps_page_dma->ps_page_dma[j],
|
||||
PAGE_SIZE, PCI_DMA_FROMDEVICE);
|
||||
ps_page_dma->ps_page_dma[j] = 0;
|
||||
skb_fill_page_desc(skb, j, ps_page->ps_page[j], 0,
|
||||
length);
|
||||
ps_page->ps_page[j] = NULL;
|
||||
skb->len += length;
|
||||
skb->data_len += length;
|
||||
skb->truesize += length;
|
||||
}
|
||||
|
||||
/* strip the ethernet crc, problem is we're using pages now so
|
||||
* this whole operation can get a little cpu intensive */
|
||||
pskb_trim(skb, skb->len - 4);
|
||||
|
||||
copydone:
|
||||
total_rx_bytes += skb->len;
|
||||
total_rx_packets++;
|
||||
|
||||
e1000_rx_checksum(adapter, staterr,
|
||||
le16_to_cpu(rx_desc->wb.lower.hi_dword.csum_ip.csum), skb);
|
||||
skb->protocol = eth_type_trans(skb, netdev);
|
||||
|
||||
if (likely(rx_desc->wb.upper.header_status &
|
||||
cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP)))
|
||||
adapter->rx_hdr_split++;
|
||||
|
||||
if (unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
|
||||
vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
|
||||
le16_to_cpu(rx_desc->wb.middle.vlan));
|
||||
} else {
|
||||
netif_receive_skb(skb);
|
||||
}
|
||||
|
||||
netdev->last_rx = jiffies;
|
||||
|
||||
next_desc:
|
||||
rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF);
|
||||
buffer_info->skb = NULL;
|
||||
|
||||
/* return some buffers to hardware, one at a time is too slow */
|
||||
if (unlikely(cleaned_count >= E1000_RX_BUFFER_WRITE)) {
|
||||
adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);
|
||||
cleaned_count = 0;
|
||||
}
|
||||
|
||||
/* use prefetched values */
|
||||
rx_desc = next_rxd;
|
||||
buffer_info = next_buffer;
|
||||
|
||||
staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
|
||||
}
|
||||
rx_ring->next_to_clean = i;
|
||||
|
||||
cleaned_count = E1000_DESC_UNUSED(rx_ring);
|
||||
if (cleaned_count)
|
||||
adapter->alloc_rx_buf(adapter, rx_ring, cleaned_count);
|
||||
|
||||
adapter->total_rx_packets += total_rx_packets;
|
||||
adapter->total_rx_bytes += total_rx_bytes;
|
||||
adapter->net_stats.rx_bytes += total_rx_bytes;
|
||||
adapter->net_stats.rx_packets += total_rx_packets;
|
||||
return cleaned;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_alloc_rx_buffers - Replace used receive buffers; legacy & extended
|
||||
* @adapter: address of board private structure
|
||||
|
|
@ -4520,104 +4237,6 @@ map_skb:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_alloc_rx_buffers_ps - Replace used receive buffers; packet split
|
||||
* @adapter: address of board private structure
|
||||
**/
|
||||
|
||||
static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
|
||||
struct e1000_rx_ring *rx_ring,
|
||||
int cleaned_count)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
union e1000_rx_desc_packet_split *rx_desc;
|
||||
struct e1000_buffer *buffer_info;
|
||||
struct e1000_ps_page *ps_page;
|
||||
struct e1000_ps_page_dma *ps_page_dma;
|
||||
struct sk_buff *skb;
|
||||
unsigned int i, j;
|
||||
|
||||
i = rx_ring->next_to_use;
|
||||
buffer_info = &rx_ring->buffer_info[i];
|
||||
ps_page = &rx_ring->ps_page[i];
|
||||
ps_page_dma = &rx_ring->ps_page_dma[i];
|
||||
|
||||
while (cleaned_count--) {
|
||||
rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
|
||||
|
||||
for (j = 0; j < PS_PAGE_BUFFERS; j++) {
|
||||
if (j < adapter->rx_ps_pages) {
|
||||
if (likely(!ps_page->ps_page[j])) {
|
||||
ps_page->ps_page[j] =
|
||||
alloc_page(GFP_ATOMIC);
|
||||
if (unlikely(!ps_page->ps_page[j])) {
|
||||
adapter->alloc_rx_buff_failed++;
|
||||
goto no_buffers;
|
||||
}
|
||||
ps_page_dma->ps_page_dma[j] =
|
||||
pci_map_page(pdev,
|
||||
ps_page->ps_page[j],
|
||||
0, PAGE_SIZE,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
}
|
||||
/* Refresh the desc even if buffer_addrs didn't
|
||||
* change because each write-back erases
|
||||
* this info.
|
||||
*/
|
||||
rx_desc->read.buffer_addr[j+1] =
|
||||
cpu_to_le64(ps_page_dma->ps_page_dma[j]);
|
||||
} else
|
||||
rx_desc->read.buffer_addr[j+1] = ~cpu_to_le64(0);
|
||||
}
|
||||
|
||||
skb = netdev_alloc_skb(netdev,
|
||||
adapter->rx_ps_bsize0 + NET_IP_ALIGN);
|
||||
|
||||
if (unlikely(!skb)) {
|
||||
adapter->alloc_rx_buff_failed++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Make buffer alignment 2 beyond a 16 byte boundary
|
||||
* this will result in a 16 byte aligned IP header after
|
||||
* the 14 byte MAC header is removed
|
||||
*/
|
||||
skb_reserve(skb, NET_IP_ALIGN);
|
||||
|
||||
buffer_info->skb = skb;
|
||||
buffer_info->length = adapter->rx_ps_bsize0;
|
||||
buffer_info->dma = pci_map_single(pdev, skb->data,
|
||||
adapter->rx_ps_bsize0,
|
||||
PCI_DMA_FROMDEVICE);
|
||||
|
||||
rx_desc->read.buffer_addr[0] = cpu_to_le64(buffer_info->dma);
|
||||
|
||||
if (unlikely(++i == rx_ring->count)) i = 0;
|
||||
buffer_info = &rx_ring->buffer_info[i];
|
||||
ps_page = &rx_ring->ps_page[i];
|
||||
ps_page_dma = &rx_ring->ps_page_dma[i];
|
||||
}
|
||||
|
||||
no_buffers:
|
||||
if (likely(rx_ring->next_to_use != i)) {
|
||||
rx_ring->next_to_use = i;
|
||||
if (unlikely(i-- == 0)) i = (rx_ring->count - 1);
|
||||
|
||||
/* Force memory writes to complete before letting h/w
|
||||
* know there are new descriptors to fetch. (Only
|
||||
* applicable for weak-ordered memory model archs,
|
||||
* such as IA-64). */
|
||||
wmb();
|
||||
/* Hardware increments by 16 bytes, but packet split
|
||||
* descriptors are 32 bytes...so we increment tail
|
||||
* twice as much.
|
||||
*/
|
||||
writel(i<<1, hw->hw_addr + rx_ring->rdt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_smartspeed - Workaround for SmartSpeed on 82541 and 82547 controllers.
|
||||
* @adapter:
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
* 82573V Gigabit Ethernet Controller (Copper)
|
||||
* 82573E Gigabit Ethernet Controller (Copper)
|
||||
* 82573L Gigabit Ethernet Controller
|
||||
* 82574L Gigabit Network Connection
|
||||
*/
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
|
@ -54,6 +55,8 @@
|
|||
|
||||
#define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000
|
||||
|
||||
#define E1000_NVM_INIT_CTRL2_MNGM 0x6000 /* Manageability Operation Mode mask */
|
||||
|
||||
static s32 e1000_get_phy_id_82571(struct e1000_hw *hw);
|
||||
static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw);
|
||||
static s32 e1000_setup_fiber_serdes_link_82571(struct e1000_hw *hw);
|
||||
|
|
@ -63,6 +66,8 @@ static s32 e1000_fix_nvm_checksum_82571(struct e1000_hw *hw);
|
|||
static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw);
|
||||
static s32 e1000_setup_link_82571(struct e1000_hw *hw);
|
||||
static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw);
|
||||
static bool e1000_check_mng_mode_82574(struct e1000_hw *hw);
|
||||
static s32 e1000_led_on_82574(struct e1000_hw *hw);
|
||||
|
||||
/**
|
||||
* e1000_init_phy_params_82571 - Init PHY func ptrs.
|
||||
|
|
@ -92,6 +97,9 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
|
|||
case e1000_82573:
|
||||
phy->type = e1000_phy_m88;
|
||||
break;
|
||||
case e1000_82574:
|
||||
phy->type = e1000_phy_bm;
|
||||
break;
|
||||
default:
|
||||
return -E1000_ERR_PHY;
|
||||
break;
|
||||
|
|
@ -111,6 +119,10 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
|
|||
if (phy->id != M88E1111_I_PHY_ID)
|
||||
return -E1000_ERR_PHY;
|
||||
break;
|
||||
case e1000_82574:
|
||||
if (phy->id != BME1000_E_PHY_ID_R2)
|
||||
return -E1000_ERR_PHY;
|
||||
break;
|
||||
default:
|
||||
return -E1000_ERR_PHY;
|
||||
break;
|
||||
|
|
@ -150,6 +162,7 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
|
|||
|
||||
switch (hw->mac.type) {
|
||||
case e1000_82573:
|
||||
case e1000_82574:
|
||||
if (((eecd >> 15) & 0x3) == 0x3) {
|
||||
nvm->type = e1000_nvm_flash_hw;
|
||||
nvm->word_size = 2048;
|
||||
|
|
@ -245,6 +258,17 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
|
|||
break;
|
||||
}
|
||||
|
||||
switch (hw->mac.type) {
|
||||
case e1000_82574:
|
||||
func->check_mng_mode = e1000_check_mng_mode_82574;
|
||||
func->led_on = e1000_led_on_82574;
|
||||
break;
|
||||
default:
|
||||
func->check_mng_mode = e1000e_check_mng_mode_generic;
|
||||
func->led_on = e1000e_led_on_generic;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -330,6 +354,8 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter)
|
|||
static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
|
||||
{
|
||||
struct e1000_phy_info *phy = &hw->phy;
|
||||
s32 ret_val;
|
||||
u16 phy_id = 0;
|
||||
|
||||
switch (hw->mac.type) {
|
||||
case e1000_82571:
|
||||
|
|
@ -345,6 +371,20 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
|
|||
case e1000_82573:
|
||||
return e1000e_get_phy_id(hw);
|
||||
break;
|
||||
case e1000_82574:
|
||||
ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
phy->id = (u32)(phy_id << 16);
|
||||
udelay(20);
|
||||
ret_val = e1e_rphy(hw, PHY_ID2, &phy_id);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
phy->id |= (u32)(phy_id);
|
||||
phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);
|
||||
break;
|
||||
default:
|
||||
return -E1000_ERR_PHY;
|
||||
break;
|
||||
|
|
@ -421,7 +461,7 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
|
|||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
if (hw->mac.type != e1000_82573)
|
||||
if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574)
|
||||
ret_val = e1000e_acquire_nvm(hw);
|
||||
|
||||
if (ret_val)
|
||||
|
|
@ -461,6 +501,7 @@ static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
|
|||
|
||||
switch (hw->mac.type) {
|
||||
case e1000_82573:
|
||||
case e1000_82574:
|
||||
ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
|
||||
break;
|
||||
case e1000_82571:
|
||||
|
|
@ -735,7 +776,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
|
|||
* Must acquire the MDIO ownership before MAC reset.
|
||||
* Ownership defaults to firmware after a reset.
|
||||
*/
|
||||
if (hw->mac.type == e1000_82573) {
|
||||
if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
|
||||
extcnf_ctrl = er32(EXTCNF_CTRL);
|
||||
extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
|
||||
|
||||
|
|
@ -776,7 +817,7 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
|
|||
* Need to wait for Phy configuration completion before accessing
|
||||
* NVM and Phy.
|
||||
*/
|
||||
if (hw->mac.type == e1000_82573)
|
||||
if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574)
|
||||
msleep(25);
|
||||
|
||||
/* Clear any pending interrupt events. */
|
||||
|
|
@ -843,7 +884,7 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw)
|
|||
ew32(TXDCTL(0), reg_data);
|
||||
|
||||
/* ...for both queues. */
|
||||
if (mac->type != e1000_82573) {
|
||||
if (mac->type != e1000_82573 && mac->type != e1000_82574) {
|
||||
reg_data = er32(TXDCTL(1));
|
||||
reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
|
||||
E1000_TXDCTL_FULL_TX_DESC_WB |
|
||||
|
|
@ -918,19 +959,28 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
|
|||
}
|
||||
|
||||
/* Device Control */
|
||||
if (hw->mac.type == e1000_82573) {
|
||||
if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
|
||||
reg = er32(CTRL);
|
||||
reg &= ~(1 << 29);
|
||||
ew32(CTRL, reg);
|
||||
}
|
||||
|
||||
/* Extended Device Control */
|
||||
if (hw->mac.type == e1000_82573) {
|
||||
if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
|
||||
reg = er32(CTRL_EXT);
|
||||
reg &= ~(1 << 23);
|
||||
reg |= (1 << 22);
|
||||
ew32(CTRL_EXT, reg);
|
||||
}
|
||||
|
||||
/* PCI-Ex Control Register */
|
||||
if (hw->mac.type == e1000_82574) {
|
||||
reg = er32(GCR);
|
||||
reg |= (1 << 22);
|
||||
ew32(GCR, reg);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -947,7 +997,7 @@ void e1000e_clear_vfta(struct e1000_hw *hw)
|
|||
u32 vfta_offset = 0;
|
||||
u32 vfta_bit_in_reg = 0;
|
||||
|
||||
if (hw->mac.type == e1000_82573) {
|
||||
if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
|
||||
if (hw->mng_cookie.vlan_id != 0) {
|
||||
/*
|
||||
* The VFTA is a 4096b bit-field, each identifying
|
||||
|
|
@ -975,6 +1025,48 @@ void e1000e_clear_vfta(struct e1000_hw *hw)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_check_mng_mode_82574 - Check manageability is enabled
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Reads the NVM Initialization Control Word 2 and returns true
|
||||
* (>0) if any manageability is enabled, else false (0).
|
||||
**/
|
||||
static bool e1000_check_mng_mode_82574(struct e1000_hw *hw)
|
||||
{
|
||||
u16 data;
|
||||
|
||||
e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &data);
|
||||
return (data & E1000_NVM_INIT_CTRL2_MNGM) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_led_on_82574 - Turn LED on
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Turn LED on.
|
||||
**/
|
||||
static s32 e1000_led_on_82574(struct e1000_hw *hw)
|
||||
{
|
||||
u32 ctrl;
|
||||
u32 i;
|
||||
|
||||
ctrl = hw->mac.ledctl_mode2;
|
||||
if (!(E1000_STATUS_LU & er32(STATUS))) {
|
||||
/*
|
||||
* If no link, then turn LED on by setting the invert bit
|
||||
* for each LED that's "on" (0x0E) in ledctl_mode2.
|
||||
*/
|
||||
for (i = 0; i < 4; i++)
|
||||
if (((hw->mac.ledctl_mode2 >> (i * 8)) & 0xFF) ==
|
||||
E1000_LEDCTL_MODE_LED_ON)
|
||||
ctrl |= (E1000_LEDCTL_LED0_IVRT << (i * 8));
|
||||
}
|
||||
ew32(LEDCTL, ctrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_update_mc_addr_list_82571 - Update Multicast addresses
|
||||
* @hw: pointer to the HW structure
|
||||
|
|
@ -1018,7 +1110,8 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw)
|
|||
* the default flow control setting, so we explicitly
|
||||
* set it to full.
|
||||
*/
|
||||
if (hw->mac.type == e1000_82573)
|
||||
if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
|
||||
hw->fc.type == e1000_fc_default)
|
||||
hw->fc.type = e1000_fc_full;
|
||||
|
||||
return e1000e_setup_link(hw);
|
||||
|
|
@ -1045,6 +1138,7 @@ static s32 e1000_setup_copper_link_82571(struct e1000_hw *hw)
|
|||
|
||||
switch (hw->phy.type) {
|
||||
case e1000_phy_m88:
|
||||
case e1000_phy_bm:
|
||||
ret_val = e1000e_copper_link_setup_m88(hw);
|
||||
break;
|
||||
case e1000_phy_igp_2:
|
||||
|
|
@ -1114,11 +1208,10 @@ static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
if (hw->mac.type == e1000_82573 &&
|
||||
if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
|
||||
*data == ID_LED_RESERVED_F746)
|
||||
*data = ID_LED_DEFAULT_82573;
|
||||
else if (*data == ID_LED_RESERVED_0000 ||
|
||||
*data == ID_LED_RESERVED_FFFF)
|
||||
else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
|
||||
*data = ID_LED_DEFAULT;
|
||||
|
||||
return 0;
|
||||
|
|
@ -1265,13 +1358,13 @@ static void e1000_clear_hw_cntrs_82571(struct e1000_hw *hw)
|
|||
}
|
||||
|
||||
static struct e1000_mac_operations e82571_mac_ops = {
|
||||
.mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
|
||||
/* .check_mng_mode: mac type dependent */
|
||||
/* .check_for_link: media type dependent */
|
||||
.cleanup_led = e1000e_cleanup_led_generic,
|
||||
.clear_hw_cntrs = e1000_clear_hw_cntrs_82571,
|
||||
.get_bus_info = e1000e_get_bus_info_pcie,
|
||||
/* .get_link_up_info: media type dependent */
|
||||
.led_on = e1000e_led_on_generic,
|
||||
/* .led_on: mac type dependent */
|
||||
.led_off = e1000e_led_off_generic,
|
||||
.update_mc_addr_list = e1000_update_mc_addr_list_82571,
|
||||
.reset_hw = e1000_reset_hw_82571,
|
||||
|
|
@ -1312,6 +1405,22 @@ static struct e1000_phy_operations e82_phy_ops_m88 = {
|
|||
.write_phy_reg = e1000e_write_phy_reg_m88,
|
||||
};
|
||||
|
||||
static struct e1000_phy_operations e82_phy_ops_bm = {
|
||||
.acquire_phy = e1000_get_hw_semaphore_82571,
|
||||
.check_reset_block = e1000e_check_reset_block_generic,
|
||||
.commit_phy = e1000e_phy_sw_reset,
|
||||
.force_speed_duplex = e1000e_phy_force_speed_duplex_m88,
|
||||
.get_cfg_done = e1000e_get_cfg_done,
|
||||
.get_cable_length = e1000e_get_cable_length_m88,
|
||||
.get_phy_info = e1000e_get_phy_info_m88,
|
||||
.read_phy_reg = e1000e_read_phy_reg_bm2,
|
||||
.release_phy = e1000_put_hw_semaphore_82571,
|
||||
.reset_phy = e1000e_phy_hw_reset_generic,
|
||||
.set_d0_lplu_state = e1000_set_d0_lplu_state_82571,
|
||||
.set_d3_lplu_state = e1000e_set_d3_lplu_state,
|
||||
.write_phy_reg = e1000e_write_phy_reg_bm2,
|
||||
};
|
||||
|
||||
static struct e1000_nvm_operations e82571_nvm_ops = {
|
||||
.acquire_nvm = e1000_acquire_nvm_82571,
|
||||
.read_nvm = e1000e_read_nvm_eerd,
|
||||
|
|
@ -1375,3 +1484,21 @@ struct e1000_info e1000_82573_info = {
|
|||
.nvm_ops = &e82571_nvm_ops,
|
||||
};
|
||||
|
||||
struct e1000_info e1000_82574_info = {
|
||||
.mac = e1000_82574,
|
||||
.flags = FLAG_HAS_HW_VLAN_FILTER
|
||||
| FLAG_HAS_MSIX
|
||||
| FLAG_HAS_JUMBO_FRAMES
|
||||
| FLAG_HAS_WOL
|
||||
| FLAG_APME_IN_CTRL3
|
||||
| FLAG_RX_CSUM_ENABLED
|
||||
| FLAG_HAS_SMART_POWER_DOWN
|
||||
| FLAG_HAS_AMT
|
||||
| FLAG_HAS_CTRLEXT_ON_LOAD,
|
||||
.pba = 20,
|
||||
.get_variants = e1000_get_variants_82571,
|
||||
.mac_ops = &e82571_mac_ops,
|
||||
.phy_ops = &e82_phy_ops_bm,
|
||||
.nvm_ops = &e82571_nvm_ops,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -71,9 +71,11 @@
|
|||
#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */
|
||||
#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
|
||||
#define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000
|
||||
#define E1000_CTRL_EXT_EIAME 0x01000000
|
||||
#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
|
||||
#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
|
||||
#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
|
||||
#define E1000_CTRL_EXT_PBA_CLR 0x80000000 /* PBA Clear */
|
||||
|
||||
/* Receive Descriptor bit definitions */
|
||||
#define E1000_RXD_STAT_DD 0x01 /* Descriptor Done */
|
||||
|
|
@ -299,6 +301,7 @@
|
|||
#define E1000_RXCSUM_IPPCSE 0x00001000 /* IP payload checksum enable */
|
||||
|
||||
/* Header split receive */
|
||||
#define E1000_RFCTL_ACK_DIS 0x00001000
|
||||
#define E1000_RFCTL_EXTEN 0x00008000
|
||||
#define E1000_RFCTL_IPV6_EX_DIS 0x00010000
|
||||
#define E1000_RFCTL_NEW_IPV6_EXT_DIS 0x00020000
|
||||
|
|
@ -363,6 +366,11 @@
|
|||
#define E1000_ICR_RXDMT0 0x00000010 /* Rx desc min. threshold (0) */
|
||||
#define E1000_ICR_RXT0 0x00000080 /* Rx timer intr (ring 0) */
|
||||
#define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */
|
||||
#define E1000_ICR_RXQ0 0x00100000 /* Rx Queue 0 Interrupt */
|
||||
#define E1000_ICR_RXQ1 0x00200000 /* Rx Queue 1 Interrupt */
|
||||
#define E1000_ICR_TXQ0 0x00400000 /* Tx Queue 0 Interrupt */
|
||||
#define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */
|
||||
#define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */
|
||||
|
||||
/*
|
||||
* This defines the bits that are set in the Interrupt Mask
|
||||
|
|
@ -386,6 +394,11 @@
|
|||
#define E1000_IMS_RXSEQ E1000_ICR_RXSEQ /* Rx sequence error */
|
||||
#define E1000_IMS_RXDMT0 E1000_ICR_RXDMT0 /* Rx desc min. threshold */
|
||||
#define E1000_IMS_RXT0 E1000_ICR_RXT0 /* Rx timer intr */
|
||||
#define E1000_IMS_RXQ0 E1000_ICR_RXQ0 /* Rx Queue 0 Interrupt */
|
||||
#define E1000_IMS_RXQ1 E1000_ICR_RXQ1 /* Rx Queue 1 Interrupt */
|
||||
#define E1000_IMS_TXQ0 E1000_ICR_TXQ0 /* Tx Queue 0 Interrupt */
|
||||
#define E1000_IMS_TXQ1 E1000_ICR_TXQ1 /* Tx Queue 1 Interrupt */
|
||||
#define E1000_IMS_OTHER E1000_ICR_OTHER /* Other Interrupts */
|
||||
|
||||
/* Interrupt Cause Set */
|
||||
#define E1000_ICS_LSC E1000_ICR_LSC /* Link Status Change */
|
||||
|
|
@ -505,6 +518,7 @@
|
|||
#define NWAY_LPAR_ASM_DIR 0x0800 /* LP Asymmetric Pause Direction bit */
|
||||
|
||||
/* Autoneg Expansion Register */
|
||||
#define NWAY_ER_LP_NWAY_CAPS 0x0001 /* LP has Auto Neg Capability */
|
||||
|
||||
/* 1000BASE-T Control Register */
|
||||
#define CR_1000T_HD_CAPS 0x0100 /* Advertise 1000T HD capability */
|
||||
|
|
@ -540,6 +554,7 @@
|
|||
#define E1000_EECD_DO 0x00000008 /* NVM Data Out */
|
||||
#define E1000_EECD_REQ 0x00000040 /* NVM Access Request */
|
||||
#define E1000_EECD_GNT 0x00000080 /* NVM Access Grant */
|
||||
#define E1000_EECD_PRES 0x00000100 /* NVM Present */
|
||||
#define E1000_EECD_SIZE 0x00000200 /* NVM Size (0=64 word 1=256 word) */
|
||||
/* NVM Addressing bits based on type (0-small, 1-large) */
|
||||
#define E1000_EECD_ADDR_BITS 0x00000400
|
||||
|
|
|
|||
|
|
@ -62,6 +62,11 @@ struct e1000_info;
|
|||
e_printk(KERN_NOTICE, adapter, format, ## arg)
|
||||
|
||||
|
||||
/* Interrupt modes, as used by the IntMode paramter */
|
||||
#define E1000E_INT_MODE_LEGACY 0
|
||||
#define E1000E_INT_MODE_MSI 1
|
||||
#define E1000E_INT_MODE_MSIX 2
|
||||
|
||||
/* Tx/Rx descriptor defines */
|
||||
#define E1000_DEFAULT_TXD 256
|
||||
#define E1000_MAX_TXD 4096
|
||||
|
|
@ -95,9 +100,11 @@ enum e1000_boards {
|
|||
board_82571,
|
||||
board_82572,
|
||||
board_82573,
|
||||
board_82574,
|
||||
board_80003es2lan,
|
||||
board_ich8lan,
|
||||
board_ich9lan,
|
||||
board_ich10lan,
|
||||
};
|
||||
|
||||
struct e1000_queue_stats {
|
||||
|
|
@ -146,6 +153,12 @@ struct e1000_ring {
|
|||
/* array of buffer information structs */
|
||||
struct e1000_buffer *buffer_info;
|
||||
|
||||
char name[IFNAMSIZ + 5];
|
||||
u32 ims_val;
|
||||
u32 itr_val;
|
||||
u16 itr_register;
|
||||
int set_itr;
|
||||
|
||||
struct sk_buff *rx_skb_top;
|
||||
|
||||
struct e1000_queue_stats stats;
|
||||
|
|
@ -257,7 +270,6 @@ struct e1000_adapter {
|
|||
struct net_device *netdev;
|
||||
struct pci_dev *pdev;
|
||||
struct net_device_stats net_stats;
|
||||
spinlock_t stats_lock; /* prevent concurrent stats updates */
|
||||
|
||||
/* structs defined in e1000_hw.h */
|
||||
struct e1000_hw hw;
|
||||
|
|
@ -274,6 +286,9 @@ struct e1000_adapter {
|
|||
u32 test_icr;
|
||||
|
||||
u32 msg_enable;
|
||||
struct msix_entry *msix_entries;
|
||||
int int_mode;
|
||||
u32 eiac_mask;
|
||||
|
||||
u32 eeprom_wol;
|
||||
u32 wol;
|
||||
|
|
@ -284,6 +299,8 @@ struct e1000_adapter {
|
|||
unsigned long led_status;
|
||||
|
||||
unsigned int flags;
|
||||
struct work_struct downshift_task;
|
||||
struct work_struct update_phy_task;
|
||||
};
|
||||
|
||||
struct e1000_info {
|
||||
|
|
@ -305,7 +322,9 @@ struct e1000_info {
|
|||
#define FLAG_HAS_CTRLEXT_ON_LOAD (1 << 5)
|
||||
#define FLAG_HAS_SWSM_ON_LOAD (1 << 6)
|
||||
#define FLAG_HAS_JUMBO_FRAMES (1 << 7)
|
||||
#define FLAG_READ_ONLY_NVM (1 << 8)
|
||||
#define FLAG_IS_ICH (1 << 9)
|
||||
#define FLAG_HAS_MSIX (1 << 10)
|
||||
#define FLAG_HAS_SMART_POWER_DOWN (1 << 11)
|
||||
#define FLAG_IS_QUAD_PORT_A (1 << 12)
|
||||
#define FLAG_IS_QUAD_PORT (1 << 13)
|
||||
|
|
@ -364,6 +383,8 @@ extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter);
|
|||
extern void e1000e_free_rx_resources(struct e1000_adapter *adapter);
|
||||
extern void e1000e_free_tx_resources(struct e1000_adapter *adapter);
|
||||
extern void e1000e_update_stats(struct e1000_adapter *adapter);
|
||||
extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter);
|
||||
extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter);
|
||||
|
||||
extern unsigned int copybreak;
|
||||
|
||||
|
|
@ -372,8 +393,10 @@ extern char *e1000e_get_hw_dev_name(struct e1000_hw *hw);
|
|||
extern struct e1000_info e1000_82571_info;
|
||||
extern struct e1000_info e1000_82572_info;
|
||||
extern struct e1000_info e1000_82573_info;
|
||||
extern struct e1000_info e1000_82574_info;
|
||||
extern struct e1000_info e1000_ich8_info;
|
||||
extern struct e1000_info e1000_ich9_info;
|
||||
extern struct e1000_info e1000_ich10_info;
|
||||
extern struct e1000_info e1000_es2_info;
|
||||
|
||||
extern s32 e1000e_read_pba_num(struct e1000_hw *hw, u32 *pba_num);
|
||||
|
|
@ -385,6 +408,7 @@ extern bool e1000e_enable_mng_pass_thru(struct e1000_hw *hw);
|
|||
extern bool e1000e_get_laa_state_82571(struct e1000_hw *hw);
|
||||
extern void e1000e_set_laa_state_82571(struct e1000_hw *hw, bool state);
|
||||
|
||||
extern void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw);
|
||||
extern void e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
|
||||
bool state);
|
||||
extern void e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw);
|
||||
|
|
@ -446,10 +470,13 @@ extern s32 e1000e_get_cable_length_m88(struct e1000_hw *hw);
|
|||
extern s32 e1000e_get_phy_info_m88(struct e1000_hw *hw);
|
||||
extern s32 e1000e_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data);
|
||||
extern s32 e1000e_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data);
|
||||
extern s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw);
|
||||
extern enum e1000_phy_type e1000e_get_phy_type_from_id(u32 phy_id);
|
||||
extern s32 e1000e_determine_phy_address(struct e1000_hw *hw);
|
||||
extern s32 e1000e_write_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 data);
|
||||
extern s32 e1000e_read_phy_reg_bm(struct e1000_hw *hw, u32 offset, u16 *data);
|
||||
extern s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data);
|
||||
extern s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data);
|
||||
extern void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl);
|
||||
extern s32 e1000e_write_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 data);
|
||||
extern s32 e1000e_read_kmrn_reg(struct e1000_hw *hw, u32 offset, u16 *data);
|
||||
|
|
@ -520,7 +547,12 @@ static inline s32 e1000_get_phy_info(struct e1000_hw *hw)
|
|||
return hw->phy.ops.get_phy_info(hw);
|
||||
}
|
||||
|
||||
extern bool e1000e_check_mng_mode(struct e1000_hw *hw);
|
||||
static inline s32 e1000e_check_mng_mode(struct e1000_hw *hw)
|
||||
{
|
||||
return hw->mac.ops.check_mng_mode(hw);
|
||||
}
|
||||
|
||||
extern bool e1000e_check_mng_mode_generic(struct e1000_hw *hw);
|
||||
extern bool e1000e_enable_tx_pkt_filtering(struct e1000_hw *hw);
|
||||
extern s32 e1000e_mng_write_dhcp_info(struct e1000_hw *hw, u8 *buffer, u16 length);
|
||||
|
||||
|
|
|
|||
|
|
@ -1247,7 +1247,7 @@ static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw)
|
|||
}
|
||||
|
||||
static struct e1000_mac_operations es2_mac_ops = {
|
||||
.mng_mode_enab = E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
|
||||
.check_mng_mode = e1000e_check_mng_mode_generic,
|
||||
/* check_for_link dependent on media type */
|
||||
.cleanup_led = e1000e_cleanup_led_generic,
|
||||
.clear_hw_cntrs = e1000_clear_hw_cntrs_80003es2lan,
|
||||
|
|
|
|||
|
|
@ -432,6 +432,10 @@ static void e1000_get_regs(struct net_device *netdev,
|
|||
regs_buff[11] = er32(TIDV);
|
||||
|
||||
regs_buff[12] = adapter->hw.phy.type; /* PHY type (IGP=1, M88=0) */
|
||||
|
||||
/* ethtool doesn't use anything past this point, so all this
|
||||
* code is likely legacy junk for apps that may or may not
|
||||
* exist */
|
||||
if (hw->phy.type == e1000_phy_m88) {
|
||||
e1e_rphy(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
|
||||
regs_buff[13] = (u32)phy_data; /* cable length */
|
||||
|
|
@ -447,7 +451,7 @@ static void e1000_get_regs(struct net_device *netdev,
|
|||
regs_buff[22] = adapter->phy_stats.receive_errors;
|
||||
regs_buff[23] = regs_buff[13]; /* mdix mode */
|
||||
}
|
||||
regs_buff[21] = adapter->phy_stats.idle_errors; /* phy idle errors */
|
||||
regs_buff[21] = 0; /* was idle_errors */
|
||||
e1e_rphy(hw, PHY_1000T_STATUS, &phy_data);
|
||||
regs_buff[24] = (u32)phy_data; /* phy local receiver status */
|
||||
regs_buff[25] = regs_buff[24]; /* phy remote receiver status */
|
||||
|
|
@ -529,6 +533,9 @@ static int e1000_set_eeprom(struct net_device *netdev,
|
|||
if (eeprom->magic != (adapter->pdev->vendor | (adapter->pdev->device << 16)))
|
||||
return -EFAULT;
|
||||
|
||||
if (adapter->flags & FLAG_READ_ONLY_NVM)
|
||||
return -EINVAL;
|
||||
|
||||
max_len = hw->nvm.word_size * 2;
|
||||
|
||||
first_word = eeprom->offset >> 1;
|
||||
|
|
@ -568,6 +575,7 @@ static int e1000_set_eeprom(struct net_device *netdev,
|
|||
* and flush shadow RAM for 82573 controllers
|
||||
*/
|
||||
if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) ||
|
||||
(hw->mac.type == e1000_82574) ||
|
||||
(hw->mac.type == e1000_82573)))
|
||||
e1000e_update_nvm_checksum(hw);
|
||||
|
||||
|
|
@ -779,8 +787,10 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
|
|||
toggle = 0x7FFFF3FF;
|
||||
break;
|
||||
case e1000_82573:
|
||||
case e1000_82574:
|
||||
case e1000_ich8lan:
|
||||
case e1000_ich9lan:
|
||||
case e1000_ich10lan:
|
||||
toggle = 0x7FFFF033;
|
||||
break;
|
||||
default:
|
||||
|
|
@ -833,7 +843,9 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
|
|||
REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF);
|
||||
for (i = 0; i < mac->rar_entry_count; i++)
|
||||
REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1),
|
||||
0x8003FFFF, 0xFFFFFFFF);
|
||||
((mac->type == e1000_ich10lan) ?
|
||||
0x8007FFFF : 0x8003FFFF),
|
||||
0xFFFFFFFF);
|
||||
|
||||
for (i = 0; i < mac->mta_reg_count; i++)
|
||||
REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF);
|
||||
|
|
@ -884,10 +896,18 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
|
|||
u32 shared_int = 1;
|
||||
u32 irq = adapter->pdev->irq;
|
||||
int i;
|
||||
int ret_val = 0;
|
||||
int int_mode = E1000E_INT_MODE_LEGACY;
|
||||
|
||||
*data = 0;
|
||||
|
||||
/* NOTE: we don't test MSI interrupts here, yet */
|
||||
/* NOTE: we don't test MSI/MSI-X interrupts here, yet */
|
||||
if (adapter->int_mode == E1000E_INT_MODE_MSIX) {
|
||||
int_mode = adapter->int_mode;
|
||||
e1000e_reset_interrupt_capability(adapter);
|
||||
adapter->int_mode = E1000E_INT_MODE_LEGACY;
|
||||
e1000e_set_interrupt_capability(adapter);
|
||||
}
|
||||
/* Hook up test interrupt handler just for this test */
|
||||
if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name,
|
||||
netdev)) {
|
||||
|
|
@ -895,7 +915,8 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
|
|||
} else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED,
|
||||
netdev->name, netdev)) {
|
||||
*data = 1;
|
||||
return -1;
|
||||
ret_val = -1;
|
||||
goto out;
|
||||
}
|
||||
e_info("testing %s interrupt\n", (shared_int ? "shared" : "unshared"));
|
||||
|
||||
|
|
@ -905,12 +926,23 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
|
|||
|
||||
/* Test each interrupt */
|
||||
for (i = 0; i < 10; i++) {
|
||||
if ((adapter->flags & FLAG_IS_ICH) && (i == 8))
|
||||
continue;
|
||||
|
||||
/* Interrupt to test */
|
||||
mask = 1 << i;
|
||||
|
||||
if (adapter->flags & FLAG_IS_ICH) {
|
||||
switch (mask) {
|
||||
case E1000_ICR_RXSEQ:
|
||||
continue;
|
||||
case 0x00000100:
|
||||
if (adapter->hw.mac.type == e1000_ich8lan ||
|
||||
adapter->hw.mac.type == e1000_ich9lan)
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!shared_int) {
|
||||
/*
|
||||
* Disable the interrupt to be reported in
|
||||
|
|
@ -974,7 +1006,14 @@ static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data)
|
|||
/* Unhook test interrupt handler */
|
||||
free_irq(irq, netdev);
|
||||
|
||||
return *data;
|
||||
out:
|
||||
if (int_mode == E1000E_INT_MODE_MSIX) {
|
||||
e1000e_reset_interrupt_capability(adapter);
|
||||
adapter->int_mode = int_mode;
|
||||
e1000e_set_interrupt_capability(adapter);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static void e1000_free_desc_rings(struct e1000_adapter *adapter)
|
||||
|
|
@ -1755,11 +1794,13 @@ static void e1000_led_blink_callback(unsigned long data)
|
|||
static int e1000_phys_id(struct net_device *netdev, u32 data)
|
||||
{
|
||||
struct e1000_adapter *adapter = netdev_priv(netdev);
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
|
||||
if (!data)
|
||||
data = INT_MAX;
|
||||
|
||||
if (adapter->hw.phy.type == e1000_phy_ife) {
|
||||
if ((hw->phy.type == e1000_phy_ife) ||
|
||||
(hw->mac.type == e1000_82574)) {
|
||||
if (!adapter->blink_timer.function) {
|
||||
init_timer(&adapter->blink_timer);
|
||||
adapter->blink_timer.function =
|
||||
|
|
@ -1769,16 +1810,16 @@ static int e1000_phys_id(struct net_device *netdev, u32 data)
|
|||
mod_timer(&adapter->blink_timer, jiffies);
|
||||
msleep_interruptible(data * 1000);
|
||||
del_timer_sync(&adapter->blink_timer);
|
||||
e1e_wphy(&adapter->hw,
|
||||
IFE_PHY_SPECIAL_CONTROL_LED, 0);
|
||||
if (hw->phy.type == e1000_phy_ife)
|
||||
e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0);
|
||||
} else {
|
||||
e1000e_blink_led(&adapter->hw);
|
||||
e1000e_blink_led(hw);
|
||||
msleep_interruptible(data * 1000);
|
||||
}
|
||||
|
||||
adapter->hw.mac.ops.led_off(&adapter->hw);
|
||||
hw->mac.ops.led_off(hw);
|
||||
clear_bit(E1000_LED_ON, &adapter->led_status);
|
||||
adapter->hw.mac.ops.cleanup_led(&adapter->hw);
|
||||
hw->mac.ops.cleanup_led(hw);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,11 @@ enum e1e_registers {
|
|||
E1000_ICS = 0x000C8, /* Interrupt Cause Set - WO */
|
||||
E1000_IMS = 0x000D0, /* Interrupt Mask Set - RW */
|
||||
E1000_IMC = 0x000D8, /* Interrupt Mask Clear - WO */
|
||||
E1000_EIAC_82574 = 0x000DC, /* Ext. Interrupt Auto Clear - RW */
|
||||
E1000_IAM = 0x000E0, /* Interrupt Acknowledge Auto Mask */
|
||||
E1000_IVAR = 0x000E4, /* Interrupt Vector Allocation - RW */
|
||||
E1000_EITR_82574_BASE = 0x000E8, /* Interrupt Throttling - RW */
|
||||
#define E1000_EITR_82574(_n) (E1000_EITR_82574_BASE + (_n << 2))
|
||||
E1000_RCTL = 0x00100, /* Rx Control - RW */
|
||||
E1000_FCTTV = 0x00170, /* Flow Control Transmit Timer Value - RW */
|
||||
E1000_TXCW = 0x00178, /* Tx Configuration Word - RW */
|
||||
|
|
@ -332,6 +336,7 @@ enum e1e_registers {
|
|||
#define E1000_DEV_ID_82573E 0x108B
|
||||
#define E1000_DEV_ID_82573E_IAMT 0x108C
|
||||
#define E1000_DEV_ID_82573L 0x109A
|
||||
#define E1000_DEV_ID_82574L 0x10D3
|
||||
|
||||
#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096
|
||||
#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098
|
||||
|
|
@ -346,6 +351,7 @@ enum e1e_registers {
|
|||
#define E1000_DEV_ID_ICH8_IFE_G 0x10C5
|
||||
#define E1000_DEV_ID_ICH8_IGP_M 0x104D
|
||||
#define E1000_DEV_ID_ICH9_IGP_AMT 0x10BD
|
||||
#define E1000_DEV_ID_ICH9_BM 0x10E5
|
||||
#define E1000_DEV_ID_ICH9_IGP_M_AMT 0x10F5
|
||||
#define E1000_DEV_ID_ICH9_IGP_M 0x10BF
|
||||
#define E1000_DEV_ID_ICH9_IGP_M_V 0x10CB
|
||||
|
|
@ -356,6 +362,10 @@ enum e1e_registers {
|
|||
#define E1000_DEV_ID_ICH10_R_BM_LM 0x10CC
|
||||
#define E1000_DEV_ID_ICH10_R_BM_LF 0x10CD
|
||||
#define E1000_DEV_ID_ICH10_R_BM_V 0x10CE
|
||||
#define E1000_DEV_ID_ICH10_D_BM_LM 0x10DE
|
||||
#define E1000_DEV_ID_ICH10_D_BM_LF 0x10DF
|
||||
|
||||
#define E1000_REVISION_4 4
|
||||
|
||||
#define E1000_FUNC_1 1
|
||||
|
||||
|
|
@ -363,9 +373,11 @@ enum e1000_mac_type {
|
|||
e1000_82571,
|
||||
e1000_82572,
|
||||
e1000_82573,
|
||||
e1000_82574,
|
||||
e1000_80003es2lan,
|
||||
e1000_ich8lan,
|
||||
e1000_ich9lan,
|
||||
e1000_ich10lan,
|
||||
};
|
||||
|
||||
enum e1000_media_type {
|
||||
|
|
@ -696,8 +708,7 @@ struct e1000_host_mng_command_info {
|
|||
|
||||
/* Function pointers and static data for the MAC. */
|
||||
struct e1000_mac_operations {
|
||||
u32 mng_mode_enab;
|
||||
|
||||
bool (*check_mng_mode)(struct e1000_hw *);
|
||||
s32 (*check_for_link)(struct e1000_hw *);
|
||||
s32 (*cleanup_led)(struct e1000_hw *);
|
||||
void (*clear_hw_cntrs)(struct e1000_hw *);
|
||||
|
|
|
|||
|
|
@ -43,7 +43,9 @@
|
|||
* 82567LM-2 Gigabit Network Connection
|
||||
* 82567LF-2 Gigabit Network Connection
|
||||
* 82567V-2 Gigabit Network Connection
|
||||
* 82562GT-3 10/100 Network Connection
|
||||
* 82567LF-3 Gigabit Network Connection
|
||||
* 82567LM-3 Gigabit Network Connection
|
||||
* 82567LM-4 Gigabit Network Connection
|
||||
*/
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
|
|
@ -58,6 +60,7 @@
|
|||
#define ICH_FLASH_HSFCTL 0x0006
|
||||
#define ICH_FLASH_FADDR 0x0008
|
||||
#define ICH_FLASH_FDATA0 0x0010
|
||||
#define ICH_FLASH_PR0 0x0074
|
||||
|
||||
#define ICH_FLASH_READ_COMMAND_TIMEOUT 500
|
||||
#define ICH_FLASH_WRITE_COMMAND_TIMEOUT 500
|
||||
|
|
@ -150,6 +153,19 @@ union ich8_hws_flash_regacc {
|
|||
u16 regval;
|
||||
};
|
||||
|
||||
/* ICH Flash Protected Region */
|
||||
union ich8_flash_protected_range {
|
||||
struct ich8_pr {
|
||||
u32 base:13; /* 0:12 Protected Range Base */
|
||||
u32 reserved1:2; /* 13:14 Reserved */
|
||||
u32 rpe:1; /* 15 Read Protection Enable */
|
||||
u32 limit:13; /* 16:28 Protected Range Limit */
|
||||
u32 reserved2:2; /* 29:30 Reserved */
|
||||
u32 wpe:1; /* 31 Write Protection Enable */
|
||||
} range;
|
||||
u32 regval;
|
||||
};
|
||||
|
||||
static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
|
||||
static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
|
||||
static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
|
||||
|
|
@ -157,12 +173,15 @@ static s32 e1000_check_polarity_ife_ich8lan(struct e1000_hw *hw);
|
|||
static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
|
||||
static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
|
||||
u32 offset, u8 byte);
|
||||
static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
|
||||
u8 *data);
|
||||
static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
|
||||
u16 *data);
|
||||
static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
|
||||
u8 size, u16 *data);
|
||||
static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
|
||||
static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
|
||||
static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
|
||||
|
||||
static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg)
|
||||
{
|
||||
|
|
@ -366,6 +385,9 @@ static s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_MUTEX(nvm_mutex);
|
||||
static pid_t nvm_owner = -1;
|
||||
|
||||
/**
|
||||
* e1000_acquire_swflag_ich8lan - Acquire software control flag
|
||||
* @hw: pointer to the HW structure
|
||||
|
|
@ -379,6 +401,15 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
|
|||
u32 extcnf_ctrl;
|
||||
u32 timeout = PHY_CFG_TIMEOUT;
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!mutex_trylock(&nvm_mutex)) {
|
||||
WARN(1, KERN_ERR "e1000e mutex contention. Owned by pid %d\n",
|
||||
nvm_owner);
|
||||
mutex_lock(&nvm_mutex);
|
||||
}
|
||||
nvm_owner = current->pid;
|
||||
|
||||
while (timeout) {
|
||||
extcnf_ctrl = er32(EXTCNF_CTRL);
|
||||
extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
|
||||
|
|
@ -393,6 +424,10 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
|
|||
|
||||
if (!timeout) {
|
||||
hw_dbg(hw, "FW or HW has locked the resource for too long.\n");
|
||||
extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
|
||||
ew32(EXTCNF_CTRL, extcnf_ctrl);
|
||||
nvm_owner = -1;
|
||||
mutex_unlock(&nvm_mutex);
|
||||
return -E1000_ERR_CONFIG;
|
||||
}
|
||||
|
||||
|
|
@ -414,6 +449,25 @@ static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
|
|||
extcnf_ctrl = er32(EXTCNF_CTRL);
|
||||
extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
|
||||
ew32(EXTCNF_CTRL, extcnf_ctrl);
|
||||
|
||||
nvm_owner = -1;
|
||||
mutex_unlock(&nvm_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_check_mng_mode_ich8lan - Checks management mode
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* This checks if the adapter has manageability enabled.
|
||||
* This is a function pointer entry point only called by read/write
|
||||
* routines for the PHY and NVM parts.
|
||||
**/
|
||||
static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
|
||||
{
|
||||
u32 fwsm = er32(FWSM);
|
||||
|
||||
return (fwsm & E1000_FWSM_MODE_MASK) ==
|
||||
(E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -896,6 +950,56 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
|
||||
* @hw: pointer to the HW structure
|
||||
* @bank: pointer to the variable that returns the active bank
|
||||
*
|
||||
* Reads signature byte from the NVM using the flash access registers.
|
||||
**/
|
||||
static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
|
||||
{
|
||||
struct e1000_nvm_info *nvm = &hw->nvm;
|
||||
/* flash bank size is in words */
|
||||
u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
|
||||
u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
|
||||
u8 bank_high_byte = 0;
|
||||
|
||||
if (hw->mac.type != e1000_ich10lan) {
|
||||
if (er32(EECD) & E1000_EECD_SEC1VAL)
|
||||
*bank = 1;
|
||||
else
|
||||
*bank = 0;
|
||||
} else {
|
||||
/*
|
||||
* Make sure the signature for bank 0 is valid,
|
||||
* if not check for bank1
|
||||
*/
|
||||
e1000_read_flash_byte_ich8lan(hw, act_offset, &bank_high_byte);
|
||||
if ((bank_high_byte & 0xC0) == 0x80) {
|
||||
*bank = 0;
|
||||
} else {
|
||||
/*
|
||||
* find if segment 1 is valid by verifying
|
||||
* bit 15:14 = 10b in word 0x13
|
||||
*/
|
||||
e1000_read_flash_byte_ich8lan(hw,
|
||||
act_offset + bank1_offset,
|
||||
&bank_high_byte);
|
||||
|
||||
/* bank1 has a valid signature equivalent to SEC1V */
|
||||
if ((bank_high_byte & 0xC0) == 0x80) {
|
||||
*bank = 1;
|
||||
} else {
|
||||
hw_dbg(hw, "ERROR: EEPROM not present\n");
|
||||
return -E1000_ERR_NVM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_read_nvm_ich8lan - Read word(s) from the NVM
|
||||
* @hw: pointer to the HW structure
|
||||
|
|
@ -912,6 +1016,7 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
|
|||
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
|
||||
u32 act_offset;
|
||||
s32 ret_val;
|
||||
u32 bank = 0;
|
||||
u16 i, word;
|
||||
|
||||
if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
|
||||
|
|
@ -924,10 +1029,11 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
|
|||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
/* Start with the bank offset, then add the relative offset. */
|
||||
act_offset = (er32(EECD) & E1000_EECD_SEC1VAL)
|
||||
? nvm->flash_bank_size
|
||||
: 0;
|
||||
ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
act_offset = (bank) ? nvm->flash_bank_size : 0;
|
||||
act_offset += offset;
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
|
|
@ -1074,6 +1180,29 @@ static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
|
|||
return e1000_read_flash_data_ich8lan(hw, offset, 2, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_read_flash_byte_ich8lan - Read byte from flash
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: The offset of the byte to read.
|
||||
* @data: Pointer to a byte to store the value read.
|
||||
*
|
||||
* Reads a single byte from the NVM using the flash access registers.
|
||||
**/
|
||||
static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
|
||||
u8 *data)
|
||||
{
|
||||
s32 ret_val;
|
||||
u16 word = 0;
|
||||
|
||||
ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
*data = (u8)word;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_read_flash_data_ich8lan - Read byte or word from NVM
|
||||
* @hw: pointer to the HW structure
|
||||
|
|
@ -1205,7 +1334,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
|
|||
{
|
||||
struct e1000_nvm_info *nvm = &hw->nvm;
|
||||
struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
|
||||
u32 i, act_offset, new_bank_offset, old_bank_offset;
|
||||
u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
|
||||
s32 ret_val;
|
||||
u16 data;
|
||||
|
||||
|
|
@ -1225,7 +1354,11 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
|
|||
* write to bank 0 etc. We also need to erase the segment that
|
||||
* is going to be written
|
||||
*/
|
||||
if (!(er32(EECD) & E1000_EECD_SEC1VAL)) {
|
||||
ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
if (bank == 0) {
|
||||
new_bank_offset = nvm->flash_bank_size;
|
||||
old_bank_offset = 0;
|
||||
e1000_erase_flash_bank_ich8lan(hw, 1);
|
||||
|
|
@ -1284,6 +1417,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
|
|||
* programming failed.
|
||||
*/
|
||||
if (ret_val) {
|
||||
/* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */
|
||||
hw_dbg(hw, "Flash commit failed.\n");
|
||||
e1000_release_swflag_ich8lan(hw);
|
||||
return ret_val;
|
||||
|
|
@ -1373,6 +1507,49 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
|
|||
return e1000e_validate_nvm_checksum_generic(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000e_write_protect_nvm_ich8lan - Make the NVM read-only
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* To prevent malicious write/erase of the NVM, set it to be read-only
|
||||
* so that the hardware ignores all write/erase cycles of the NVM via
|
||||
* the flash control registers. The shadow-ram copy of the NVM will
|
||||
* still be updated, however any updates to this copy will not stick
|
||||
* across driver reloads.
|
||||
**/
|
||||
void e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw)
|
||||
{
|
||||
union ich8_flash_protected_range pr0;
|
||||
union ich8_hws_flash_status hsfsts;
|
||||
u32 gfpreg;
|
||||
s32 ret_val;
|
||||
|
||||
ret_val = e1000_acquire_swflag_ich8lan(hw);
|
||||
if (ret_val)
|
||||
return;
|
||||
|
||||
gfpreg = er32flash(ICH_FLASH_GFPREG);
|
||||
|
||||
/* Write-protect GbE Sector of NVM */
|
||||
pr0.regval = er32flash(ICH_FLASH_PR0);
|
||||
pr0.range.base = gfpreg & FLASH_GFPREG_BASE_MASK;
|
||||
pr0.range.limit = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK);
|
||||
pr0.range.wpe = true;
|
||||
ew32flash(ICH_FLASH_PR0, pr0.regval);
|
||||
|
||||
/*
|
||||
* Lock down a subset of GbE Flash Control Registers, e.g.
|
||||
* PR0 to prevent the write-protection from being lifted.
|
||||
* Once FLOCKDN is set, the registers protected by it cannot
|
||||
* be written until FLOCKDN is cleared by a hardware reset.
|
||||
*/
|
||||
hsfsts.regval = er16flash(ICH_FLASH_HSFSTS);
|
||||
hsfsts.hsf_status.flockdn = true;
|
||||
ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval);
|
||||
|
||||
e1000_release_swflag_ich8lan(hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_write_flash_data_ich8lan - Writes bytes to the NVM
|
||||
* @hw: pointer to the HW structure
|
||||
|
|
@ -1720,6 +1897,9 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
|
|||
ew32(CTRL, (ctrl | E1000_CTRL_RST));
|
||||
msleep(20);
|
||||
|
||||
/* release the swflag because it is not reset by hardware reset */
|
||||
e1000_release_swflag_ich8lan(hw);
|
||||
|
||||
ret_val = e1000e_get_auto_rd_done(hw);
|
||||
if (ret_val) {
|
||||
/*
|
||||
|
|
@ -2189,13 +2369,14 @@ void e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
|
|||
* 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
|
||||
* to a lower speed.
|
||||
*
|
||||
* Should only be called for ICH9 devices.
|
||||
* Should only be called for ICH9 and ICH10 devices.
|
||||
**/
|
||||
void e1000e_disable_gig_wol_ich8lan(struct e1000_hw *hw)
|
||||
{
|
||||
u32 phy_ctrl;
|
||||
|
||||
if (hw->mac.type == e1000_ich9lan) {
|
||||
if ((hw->mac.type == e1000_ich10lan) ||
|
||||
(hw->mac.type == e1000_ich9lan)) {
|
||||
phy_ctrl = er32(PHY_CTRL);
|
||||
phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
|
||||
E1000_PHY_CTRL_GBE_DISABLE;
|
||||
|
|
@ -2252,6 +2433,39 @@ static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_get_cfg_done_ich8lan - Read config done bit
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Read the management control register for the config done bit for
|
||||
* completion status. NOTE: silicon which is EEPROM-less will fail trying
|
||||
* to read the config done bit, so an error is *ONLY* logged and returns
|
||||
* E1000_SUCCESS. If we were to return with error, EEPROM-less silicon
|
||||
* would not be able to be reset or change link.
|
||||
**/
|
||||
static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
|
||||
{
|
||||
u32 bank = 0;
|
||||
|
||||
e1000e_get_cfg_done(hw);
|
||||
|
||||
/* If EEPROM is not marked present, init the IGP 3 PHY manually */
|
||||
if (hw->mac.type != e1000_ich10lan) {
|
||||
if (((er32(EECD) & E1000_EECD_PRES) == 0) &&
|
||||
(hw->phy.type == e1000_phy_igp_3)) {
|
||||
e1000e_phy_init_script_igp3(hw);
|
||||
}
|
||||
} else {
|
||||
if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
|
||||
/* Maybe we should do a basic PHY config */
|
||||
hw_dbg(hw, "EEPROM not present\n");
|
||||
return -E1000_ERR_CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
|
||||
* @hw: pointer to the HW structure
|
||||
|
|
@ -2282,7 +2496,7 @@ static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
|
|||
}
|
||||
|
||||
static struct e1000_mac_operations ich8_mac_ops = {
|
||||
.mng_mode_enab = E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT,
|
||||
.check_mng_mode = e1000_check_mng_mode_ich8lan,
|
||||
.check_for_link = e1000e_check_for_copper_link,
|
||||
.cleanup_led = e1000_cleanup_led_ich8lan,
|
||||
.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan,
|
||||
|
|
@ -2302,7 +2516,7 @@ static struct e1000_phy_operations ich8_phy_ops = {
|
|||
.check_reset_block = e1000_check_reset_block_ich8lan,
|
||||
.commit_phy = NULL,
|
||||
.force_speed_duplex = e1000_phy_force_speed_duplex_ich8lan,
|
||||
.get_cfg_done = e1000e_get_cfg_done,
|
||||
.get_cfg_done = e1000_get_cfg_done_ich8lan,
|
||||
.get_cable_length = e1000e_get_cable_length_igp_2,
|
||||
.get_phy_info = e1000_get_phy_info_ich8lan,
|
||||
.read_phy_reg = e1000e_read_phy_reg_igp,
|
||||
|
|
@ -2357,3 +2571,20 @@ struct e1000_info e1000_ich9_info = {
|
|||
.nvm_ops = &ich8_nvm_ops,
|
||||
};
|
||||
|
||||
struct e1000_info e1000_ich10_info = {
|
||||
.mac = e1000_ich10lan,
|
||||
.flags = FLAG_HAS_JUMBO_FRAMES
|
||||
| FLAG_IS_ICH
|
||||
| FLAG_HAS_WOL
|
||||
| FLAG_RX_CSUM_ENABLED
|
||||
| FLAG_HAS_CTRLEXT_ON_LOAD
|
||||
| FLAG_HAS_AMT
|
||||
| FLAG_HAS_ERT
|
||||
| FLAG_HAS_FLASH
|
||||
| FLAG_APME_IN_WUC,
|
||||
.pba = 10,
|
||||
.get_variants = e1000_get_variants_ich8lan,
|
||||
.mac_ops = &ich8_mac_ops,
|
||||
.phy_ops = &ich8_phy_ops,
|
||||
.nvm_ops = &ich8_nvm_ops,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2012,6 +2012,7 @@ s32 e1000e_write_nvm_spi(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
|
|||
}
|
||||
|
||||
msleep(10);
|
||||
nvm->ops.release_nvm(hw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -2222,17 +2223,18 @@ static s32 e1000_mng_enable_host_if(struct e1000_hw *hw)
|
|||
}
|
||||
|
||||
/**
|
||||
* e1000e_check_mng_mode - check management mode
|
||||
* e1000e_check_mng_mode_generic - check management mode
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Reads the firmware semaphore register and returns true (>0) if
|
||||
* manageability is enabled, else false (0).
|
||||
**/
|
||||
bool e1000e_check_mng_mode(struct e1000_hw *hw)
|
||||
bool e1000e_check_mng_mode_generic(struct e1000_hw *hw)
|
||||
{
|
||||
u32 fwsm = er32(FWSM);
|
||||
|
||||
return (fwsm & E1000_FWSM_MODE_MASK) == hw->mac.ops.mng_mode_enab;
|
||||
return (fwsm & E1000_FWSM_MODE_MASK) ==
|
||||
(E1000_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
#include "e1000.h"
|
||||
|
||||
#define DRV_VERSION "0.3.3.3-k2"
|
||||
#define DRV_VERSION "0.3.3.3-k6"
|
||||
char e1000e_driver_name[] = "e1000e";
|
||||
const char e1000e_driver_version[] = DRV_VERSION;
|
||||
|
||||
|
|
@ -55,9 +55,11 @@ static const struct e1000_info *e1000_info_tbl[] = {
|
|||
[board_82571] = &e1000_82571_info,
|
||||
[board_82572] = &e1000_82572_info,
|
||||
[board_82573] = &e1000_82573_info,
|
||||
[board_82574] = &e1000_82574_info,
|
||||
[board_80003es2lan] = &e1000_es2_info,
|
||||
[board_ich8lan] = &e1000_ich8_info,
|
||||
[board_ich9lan] = &e1000_ich9_info,
|
||||
[board_ich10lan] = &e1000_ich10_info,
|
||||
};
|
||||
|
||||
#ifdef DEBUG
|
||||
|
|
@ -1115,6 +1117,14 @@ static void e1000_clean_rx_ring(struct e1000_adapter *adapter)
|
|||
writel(0, adapter->hw.hw_addr + rx_ring->tail);
|
||||
}
|
||||
|
||||
static void e1000e_downshift_workaround(struct work_struct *work)
|
||||
{
|
||||
struct e1000_adapter *adapter = container_of(work,
|
||||
struct e1000_adapter, downshift_task);
|
||||
|
||||
e1000e_gig_downshift_workaround_ich8lan(&adapter->hw);
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_intr_msi - Interrupt Handler
|
||||
* @irq: interrupt number
|
||||
|
|
@ -1139,7 +1149,7 @@ static irqreturn_t e1000_intr_msi(int irq, void *data)
|
|||
*/
|
||||
if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
|
||||
(!(er32(STATUS) & E1000_STATUS_LU)))
|
||||
e1000e_gig_downshift_workaround_ich8lan(hw);
|
||||
schedule_work(&adapter->downshift_task);
|
||||
|
||||
/*
|
||||
* 80003ES2LAN workaround-- For packet buffer work-around on
|
||||
|
|
@ -1179,8 +1189,8 @@ static irqreturn_t e1000_intr(int irq, void *data)
|
|||
struct net_device *netdev = data;
|
||||
struct e1000_adapter *adapter = netdev_priv(netdev);
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
|
||||
u32 rctl, icr = er32(ICR);
|
||||
|
||||
if (!icr)
|
||||
return IRQ_NONE; /* Not our interrupt */
|
||||
|
||||
|
|
@ -1205,7 +1215,7 @@ static irqreturn_t e1000_intr(int irq, void *data)
|
|||
*/
|
||||
if ((adapter->flags & FLAG_LSC_GIG_SPEED_DROP) &&
|
||||
(!(er32(STATUS) & E1000_STATUS_LU)))
|
||||
e1000e_gig_downshift_workaround_ich8lan(hw);
|
||||
schedule_work(&adapter->downshift_task);
|
||||
|
||||
/*
|
||||
* 80003ES2LAN workaround--
|
||||
|
|
@ -1236,6 +1246,263 @@ static irqreturn_t e1000_intr(int irq, void *data)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t e1000_msix_other(int irq, void *data)
|
||||
{
|
||||
struct net_device *netdev = data;
|
||||
struct e1000_adapter *adapter = netdev_priv(netdev);
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
u32 icr = er32(ICR);
|
||||
|
||||
if (!(icr & E1000_ICR_INT_ASSERTED)) {
|
||||
ew32(IMS, E1000_IMS_OTHER);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (icr & adapter->eiac_mask)
|
||||
ew32(ICS, (icr & adapter->eiac_mask));
|
||||
|
||||
if (icr & E1000_ICR_OTHER) {
|
||||
if (!(icr & E1000_ICR_LSC))
|
||||
goto no_link_interrupt;
|
||||
hw->mac.get_link_status = 1;
|
||||
/* guard against interrupt when we're going down */
|
||||
if (!test_bit(__E1000_DOWN, &adapter->state))
|
||||
mod_timer(&adapter->watchdog_timer, jiffies + 1);
|
||||
}
|
||||
|
||||
no_link_interrupt:
|
||||
ew32(IMS, E1000_IMS_LSC | E1000_IMS_OTHER);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static irqreturn_t e1000_intr_msix_tx(int irq, void *data)
|
||||
{
|
||||
struct net_device *netdev = data;
|
||||
struct e1000_adapter *adapter = netdev_priv(netdev);
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct e1000_ring *tx_ring = adapter->tx_ring;
|
||||
|
||||
|
||||
adapter->total_tx_bytes = 0;
|
||||
adapter->total_tx_packets = 0;
|
||||
|
||||
if (!e1000_clean_tx_irq(adapter))
|
||||
/* Ring was not completely cleaned, so fire another interrupt */
|
||||
ew32(ICS, tx_ring->ims_val);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t e1000_intr_msix_rx(int irq, void *data)
|
||||
{
|
||||
struct net_device *netdev = data;
|
||||
struct e1000_adapter *adapter = netdev_priv(netdev);
|
||||
|
||||
/* Write the ITR value calculated at the end of the
|
||||
* previous interrupt.
|
||||
*/
|
||||
if (adapter->rx_ring->set_itr) {
|
||||
writel(1000000000 / (adapter->rx_ring->itr_val * 256),
|
||||
adapter->hw.hw_addr + adapter->rx_ring->itr_register);
|
||||
adapter->rx_ring->set_itr = 0;
|
||||
}
|
||||
|
||||
if (netif_rx_schedule_prep(netdev, &adapter->napi)) {
|
||||
adapter->total_rx_bytes = 0;
|
||||
adapter->total_rx_packets = 0;
|
||||
__netif_rx_schedule(netdev, &adapter->napi);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_configure_msix - Configure MSI-X hardware
|
||||
*
|
||||
* e1000_configure_msix sets up the hardware to properly
|
||||
* generate MSI-X interrupts.
|
||||
**/
|
||||
static void e1000_configure_msix(struct e1000_adapter *adapter)
|
||||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct e1000_ring *rx_ring = adapter->rx_ring;
|
||||
struct e1000_ring *tx_ring = adapter->tx_ring;
|
||||
int vector = 0;
|
||||
u32 ctrl_ext, ivar = 0;
|
||||
|
||||
adapter->eiac_mask = 0;
|
||||
|
||||
/* Workaround issue with spurious interrupts on 82574 in MSI-X mode */
|
||||
if (hw->mac.type == e1000_82574) {
|
||||
u32 rfctl = er32(RFCTL);
|
||||
rfctl |= E1000_RFCTL_ACK_DIS;
|
||||
ew32(RFCTL, rfctl);
|
||||
}
|
||||
|
||||
#define E1000_IVAR_INT_ALLOC_VALID 0x8
|
||||
/* Configure Rx vector */
|
||||
rx_ring->ims_val = E1000_IMS_RXQ0;
|
||||
adapter->eiac_mask |= rx_ring->ims_val;
|
||||
if (rx_ring->itr_val)
|
||||
writel(1000000000 / (rx_ring->itr_val * 256),
|
||||
hw->hw_addr + rx_ring->itr_register);
|
||||
else
|
||||
writel(1, hw->hw_addr + rx_ring->itr_register);
|
||||
ivar = E1000_IVAR_INT_ALLOC_VALID | vector;
|
||||
|
||||
/* Configure Tx vector */
|
||||
tx_ring->ims_val = E1000_IMS_TXQ0;
|
||||
vector++;
|
||||
if (tx_ring->itr_val)
|
||||
writel(1000000000 / (tx_ring->itr_val * 256),
|
||||
hw->hw_addr + tx_ring->itr_register);
|
||||
else
|
||||
writel(1, hw->hw_addr + tx_ring->itr_register);
|
||||
adapter->eiac_mask |= tx_ring->ims_val;
|
||||
ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 8);
|
||||
|
||||
/* set vector for Other Causes, e.g. link changes */
|
||||
vector++;
|
||||
ivar |= ((E1000_IVAR_INT_ALLOC_VALID | vector) << 16);
|
||||
if (rx_ring->itr_val)
|
||||
writel(1000000000 / (rx_ring->itr_val * 256),
|
||||
hw->hw_addr + E1000_EITR_82574(vector));
|
||||
else
|
||||
writel(1, hw->hw_addr + E1000_EITR_82574(vector));
|
||||
|
||||
/* Cause Tx interrupts on every write back */
|
||||
ivar |= (1 << 31);
|
||||
|
||||
ew32(IVAR, ivar);
|
||||
|
||||
/* enable MSI-X PBA support */
|
||||
ctrl_ext = er32(CTRL_EXT);
|
||||
ctrl_ext |= E1000_CTRL_EXT_PBA_CLR;
|
||||
|
||||
/* Auto-Mask Other interrupts upon ICR read */
|
||||
#define E1000_EIAC_MASK_82574 0x01F00000
|
||||
ew32(IAM, ~E1000_EIAC_MASK_82574 | E1000_IMS_OTHER);
|
||||
ctrl_ext |= E1000_CTRL_EXT_EIAME;
|
||||
ew32(CTRL_EXT, ctrl_ext);
|
||||
e1e_flush();
|
||||
}
|
||||
|
||||
void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter)
|
||||
{
|
||||
if (adapter->msix_entries) {
|
||||
pci_disable_msix(adapter->pdev);
|
||||
kfree(adapter->msix_entries);
|
||||
adapter->msix_entries = NULL;
|
||||
} else if (adapter->flags & FLAG_MSI_ENABLED) {
|
||||
pci_disable_msi(adapter->pdev);
|
||||
adapter->flags &= ~FLAG_MSI_ENABLED;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000e_set_interrupt_capability - set MSI or MSI-X if supported
|
||||
*
|
||||
* Attempt to configure interrupts using the best available
|
||||
* capabilities of the hardware and kernel.
|
||||
**/
|
||||
void e1000e_set_interrupt_capability(struct e1000_adapter *adapter)
|
||||
{
|
||||
int err;
|
||||
int numvecs, i;
|
||||
|
||||
|
||||
switch (adapter->int_mode) {
|
||||
case E1000E_INT_MODE_MSIX:
|
||||
if (adapter->flags & FLAG_HAS_MSIX) {
|
||||
numvecs = 3; /* RxQ0, TxQ0 and other */
|
||||
adapter->msix_entries = kcalloc(numvecs,
|
||||
sizeof(struct msix_entry),
|
||||
GFP_KERNEL);
|
||||
if (adapter->msix_entries) {
|
||||
for (i = 0; i < numvecs; i++)
|
||||
adapter->msix_entries[i].entry = i;
|
||||
|
||||
err = pci_enable_msix(adapter->pdev,
|
||||
adapter->msix_entries,
|
||||
numvecs);
|
||||
if (err == 0)
|
||||
return;
|
||||
}
|
||||
/* MSI-X failed, so fall through and try MSI */
|
||||
e_err("Failed to initialize MSI-X interrupts. "
|
||||
"Falling back to MSI interrupts.\n");
|
||||
e1000e_reset_interrupt_capability(adapter);
|
||||
}
|
||||
adapter->int_mode = E1000E_INT_MODE_MSI;
|
||||
/* Fall through */
|
||||
case E1000E_INT_MODE_MSI:
|
||||
if (!pci_enable_msi(adapter->pdev)) {
|
||||
adapter->flags |= FLAG_MSI_ENABLED;
|
||||
} else {
|
||||
adapter->int_mode = E1000E_INT_MODE_LEGACY;
|
||||
e_err("Failed to initialize MSI interrupts. Falling "
|
||||
"back to legacy interrupts.\n");
|
||||
}
|
||||
/* Fall through */
|
||||
case E1000E_INT_MODE_LEGACY:
|
||||
/* Don't do anything; this is the system default */
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_request_msix - Initialize MSI-X interrupts
|
||||
*
|
||||
* e1000_request_msix allocates MSI-X vectors and requests interrupts from the
|
||||
* kernel.
|
||||
**/
|
||||
static int e1000_request_msix(struct e1000_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
int err = 0, vector = 0;
|
||||
|
||||
if (strlen(netdev->name) < (IFNAMSIZ - 5))
|
||||
sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name);
|
||||
else
|
||||
memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ);
|
||||
err = request_irq(adapter->msix_entries[vector].vector,
|
||||
&e1000_intr_msix_rx, 0, adapter->rx_ring->name,
|
||||
netdev);
|
||||
if (err)
|
||||
goto out;
|
||||
adapter->rx_ring->itr_register = E1000_EITR_82574(vector);
|
||||
adapter->rx_ring->itr_val = adapter->itr;
|
||||
vector++;
|
||||
|
||||
if (strlen(netdev->name) < (IFNAMSIZ - 5))
|
||||
sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name);
|
||||
else
|
||||
memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ);
|
||||
err = request_irq(adapter->msix_entries[vector].vector,
|
||||
&e1000_intr_msix_tx, 0, adapter->tx_ring->name,
|
||||
netdev);
|
||||
if (err)
|
||||
goto out;
|
||||
adapter->tx_ring->itr_register = E1000_EITR_82574(vector);
|
||||
adapter->tx_ring->itr_val = adapter->itr;
|
||||
vector++;
|
||||
|
||||
err = request_irq(adapter->msix_entries[vector].vector,
|
||||
&e1000_msix_other, 0, netdev->name, netdev);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
e1000_configure_msix(adapter);
|
||||
return 0;
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_request_irq - initialize interrupts
|
||||
*
|
||||
|
|
@ -1245,28 +1512,32 @@ static irqreturn_t e1000_intr(int irq, void *data)
|
|||
static int e1000_request_irq(struct e1000_adapter *adapter)
|
||||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
int irq_flags = IRQF_SHARED;
|
||||
int err;
|
||||
|
||||
if (!(adapter->flags & FLAG_MSI_TEST_FAILED)) {
|
||||
err = pci_enable_msi(adapter->pdev);
|
||||
if (!err) {
|
||||
adapter->flags |= FLAG_MSI_ENABLED;
|
||||
irq_flags = 0;
|
||||
}
|
||||
if (adapter->msix_entries) {
|
||||
err = e1000_request_msix(adapter);
|
||||
if (!err)
|
||||
return err;
|
||||
/* fall back to MSI */
|
||||
e1000e_reset_interrupt_capability(adapter);
|
||||
adapter->int_mode = E1000E_INT_MODE_MSI;
|
||||
e1000e_set_interrupt_capability(adapter);
|
||||
}
|
||||
if (adapter->flags & FLAG_MSI_ENABLED) {
|
||||
err = request_irq(adapter->pdev->irq, &e1000_intr_msi, 0,
|
||||
netdev->name, netdev);
|
||||
if (!err)
|
||||
return err;
|
||||
|
||||
/* fall back to legacy interrupt */
|
||||
e1000e_reset_interrupt_capability(adapter);
|
||||
adapter->int_mode = E1000E_INT_MODE_LEGACY;
|
||||
}
|
||||
|
||||
err = request_irq(adapter->pdev->irq,
|
||||
((adapter->flags & FLAG_MSI_ENABLED) ?
|
||||
&e1000_intr_msi : &e1000_intr),
|
||||
irq_flags, netdev->name, netdev);
|
||||
if (err) {
|
||||
if (adapter->flags & FLAG_MSI_ENABLED) {
|
||||
pci_disable_msi(adapter->pdev);
|
||||
adapter->flags &= ~FLAG_MSI_ENABLED;
|
||||
}
|
||||
err = request_irq(adapter->pdev->irq, &e1000_intr, IRQF_SHARED,
|
||||
netdev->name, netdev);
|
||||
if (err)
|
||||
e_err("Unable to allocate interrupt, Error: %d\n", err);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -1275,11 +1546,21 @@ static void e1000_free_irq(struct e1000_adapter *adapter)
|
|||
{
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
|
||||
free_irq(adapter->pdev->irq, netdev);
|
||||
if (adapter->flags & FLAG_MSI_ENABLED) {
|
||||
pci_disable_msi(adapter->pdev);
|
||||
adapter->flags &= ~FLAG_MSI_ENABLED;
|
||||
if (adapter->msix_entries) {
|
||||
int vector = 0;
|
||||
|
||||
free_irq(adapter->msix_entries[vector].vector, netdev);
|
||||
vector++;
|
||||
|
||||
free_irq(adapter->msix_entries[vector].vector, netdev);
|
||||
vector++;
|
||||
|
||||
/* Other Causes interrupt vector */
|
||||
free_irq(adapter->msix_entries[vector].vector, netdev);
|
||||
return;
|
||||
}
|
||||
|
||||
free_irq(adapter->pdev->irq, netdev);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1290,6 +1571,8 @@ static void e1000_irq_disable(struct e1000_adapter *adapter)
|
|||
struct e1000_hw *hw = &adapter->hw;
|
||||
|
||||
ew32(IMC, ~0);
|
||||
if (adapter->msix_entries)
|
||||
ew32(EIAC_82574, 0);
|
||||
e1e_flush();
|
||||
synchronize_irq(adapter->pdev->irq);
|
||||
}
|
||||
|
|
@ -1301,7 +1584,12 @@ static void e1000_irq_enable(struct e1000_adapter *adapter)
|
|||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
|
||||
ew32(IMS, IMS_ENABLE_MASK);
|
||||
if (adapter->msix_entries) {
|
||||
ew32(EIAC_82574, adapter->eiac_mask & E1000_EIAC_MASK_82574);
|
||||
ew32(IMS, adapter->eiac_mask | E1000_IMS_OTHER | E1000_IMS_LSC);
|
||||
} else {
|
||||
ew32(IMS, IMS_ENABLE_MASK);
|
||||
}
|
||||
e1e_flush();
|
||||
}
|
||||
|
||||
|
|
@ -1551,9 +1839,8 @@ void e1000e_free_rx_resources(struct e1000_adapter *adapter)
|
|||
* traffic pattern. Constants in this function were computed
|
||||
* based on theoretical maximum wire speed and thresholds were set based
|
||||
* on testing data as well as attempting to minimize response time
|
||||
* while increasing bulk throughput.
|
||||
* this functionality is controlled by the InterruptThrottleRate module
|
||||
* parameter (see e1000_param.c)
|
||||
* while increasing bulk throughput. This functionality is controlled
|
||||
* by the InterruptThrottleRate module parameter.
|
||||
**/
|
||||
static unsigned int e1000_update_itr(struct e1000_adapter *adapter,
|
||||
u16 itr_setting, int packets,
|
||||
|
|
@ -1661,10 +1948,36 @@ set_itr_now:
|
|||
min(adapter->itr + (new_itr >> 2), new_itr) :
|
||||
new_itr;
|
||||
adapter->itr = new_itr;
|
||||
ew32(ITR, 1000000000 / (new_itr * 256));
|
||||
adapter->rx_ring->itr_val = new_itr;
|
||||
if (adapter->msix_entries)
|
||||
adapter->rx_ring->set_itr = 1;
|
||||
else
|
||||
ew32(ITR, 1000000000 / (new_itr * 256));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_alloc_queues - Allocate memory for all rings
|
||||
* @adapter: board private structure to initialize
|
||||
**/
|
||||
static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter)
|
||||
{
|
||||
adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
|
||||
if (!adapter->tx_ring)
|
||||
goto err;
|
||||
|
||||
adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
|
||||
if (!adapter->rx_ring)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
e_err("Unable to allocate memory for queues\n");
|
||||
kfree(adapter->rx_ring);
|
||||
kfree(adapter->tx_ring);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_clean - NAPI Rx polling callback
|
||||
* @napi: struct associated with this polling callback
|
||||
|
|
@ -1673,12 +1986,17 @@ set_itr_now:
|
|||
static int e1000_clean(struct napi_struct *napi, int budget)
|
||||
{
|
||||
struct e1000_adapter *adapter = container_of(napi, struct e1000_adapter, napi);
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct net_device *poll_dev = adapter->netdev;
|
||||
int tx_cleaned = 0, work_done = 0;
|
||||
|
||||
/* Must NOT use netdev_priv macro here. */
|
||||
adapter = poll_dev->priv;
|
||||
|
||||
if (adapter->msix_entries &&
|
||||
!(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val))
|
||||
goto clean_rx;
|
||||
|
||||
/*
|
||||
* e1000_clean is called per-cpu. This lock protects
|
||||
* tx_ring from being cleaned by multiple cpus
|
||||
|
|
@ -1690,6 +2008,7 @@ static int e1000_clean(struct napi_struct *napi, int budget)
|
|||
spin_unlock(&adapter->tx_queue_lock);
|
||||
}
|
||||
|
||||
clean_rx:
|
||||
adapter->clean_rx(adapter, &work_done, budget);
|
||||
|
||||
if (tx_cleaned)
|
||||
|
|
@ -1700,7 +2019,10 @@ static int e1000_clean(struct napi_struct *napi, int budget)
|
|||
if (adapter->itr_setting & 3)
|
||||
e1000_set_itr(adapter);
|
||||
netif_rx_complete(poll_dev, napi);
|
||||
e1000_irq_enable(adapter);
|
||||
if (adapter->msix_entries)
|
||||
ew32(IMS, adapter->rx_ring->ims_val);
|
||||
else
|
||||
e1000_irq_enable(adapter);
|
||||
}
|
||||
|
||||
return work_done;
|
||||
|
|
@ -2496,6 +2818,8 @@ int e1000e_up(struct e1000_adapter *adapter)
|
|||
clear_bit(__E1000_DOWN, &adapter->state);
|
||||
|
||||
napi_enable(&adapter->napi);
|
||||
if (adapter->msix_entries)
|
||||
e1000_configure_msix(adapter);
|
||||
e1000_irq_enable(adapter);
|
||||
|
||||
/* fire a link change interrupt to start the watchdog */
|
||||
|
|
@ -2579,29 +2903,18 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
|
|||
adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
|
||||
adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
|
||||
|
||||
adapter->tx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
|
||||
if (!adapter->tx_ring)
|
||||
goto err;
|
||||
e1000e_set_interrupt_capability(adapter);
|
||||
|
||||
adapter->rx_ring = kzalloc(sizeof(struct e1000_ring), GFP_KERNEL);
|
||||
if (!adapter->rx_ring)
|
||||
goto err;
|
||||
if (e1000_alloc_queues(adapter))
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&adapter->tx_queue_lock);
|
||||
|
||||
/* Explicitly disable IRQ since the NIC can be in any state. */
|
||||
e1000_irq_disable(adapter);
|
||||
|
||||
spin_lock_init(&adapter->stats_lock);
|
||||
|
||||
set_bit(__E1000_DOWN, &adapter->state);
|
||||
return 0;
|
||||
|
||||
err:
|
||||
e_err("Unable to allocate memory for queues\n");
|
||||
kfree(adapter->rx_ring);
|
||||
kfree(adapter->tx_ring);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2643,6 +2956,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
|
|||
|
||||
/* free the real vector and request a test handler */
|
||||
e1000_free_irq(adapter);
|
||||
e1000e_reset_interrupt_capability(adapter);
|
||||
|
||||
/* Assume that the test fails, if it succeeds then the test
|
||||
* MSI irq handler will unset this flag */
|
||||
|
|
@ -2673,6 +2987,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
|
|||
rmb();
|
||||
|
||||
if (adapter->flags & FLAG_MSI_TEST_FAILED) {
|
||||
adapter->int_mode = E1000E_INT_MODE_LEGACY;
|
||||
err = -EIO;
|
||||
e_info("MSI interrupt test failed!\n");
|
||||
}
|
||||
|
|
@ -2686,7 +3001,7 @@ static int e1000_test_msi_interrupt(struct e1000_adapter *adapter)
|
|||
/* okay so the test worked, restore settings */
|
||||
e_dbg("%s: MSI interrupt test succeeded!\n", netdev->name);
|
||||
msi_test_failed:
|
||||
/* restore the original vector, even if it failed */
|
||||
e1000e_set_interrupt_capability(adapter);
|
||||
e1000_request_irq(adapter);
|
||||
return err;
|
||||
}
|
||||
|
|
@ -2796,7 +3111,7 @@ static int e1000_open(struct net_device *netdev)
|
|||
* ignore e1000e MSI messages, which means we need to test our MSI
|
||||
* interrupt now
|
||||
*/
|
||||
{
|
||||
if (adapter->int_mode != E1000E_INT_MODE_LEGACY) {
|
||||
err = e1000_test_msi(adapter);
|
||||
if (err) {
|
||||
e_err("Interrupt allocation failed\n");
|
||||
|
|
@ -2912,6 +3227,21 @@ static int e1000_set_mac(struct net_device *netdev, void *p)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000e_update_phy_task - work thread to update phy
|
||||
* @work: pointer to our work struct
|
||||
*
|
||||
* this worker thread exists because we must acquire a
|
||||
* semaphore to read the phy, which we could msleep while
|
||||
* waiting for it, and we can't msleep in a timer.
|
||||
**/
|
||||
static void e1000e_update_phy_task(struct work_struct *work)
|
||||
{
|
||||
struct e1000_adapter *adapter = container_of(work,
|
||||
struct e1000_adapter, update_phy_task);
|
||||
e1000_get_phy_info(&adapter->hw);
|
||||
}
|
||||
|
||||
/*
|
||||
* Need to wait a few seconds after link up to get diagnostic information from
|
||||
* the phy
|
||||
|
|
@ -2919,7 +3249,7 @@ static int e1000_set_mac(struct net_device *netdev, void *p)
|
|||
static void e1000_update_phy_info(unsigned long data)
|
||||
{
|
||||
struct e1000_adapter *adapter = (struct e1000_adapter *) data;
|
||||
e1000_get_phy_info(&adapter->hw);
|
||||
schedule_work(&adapter->update_phy_task);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2930,10 +3260,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
|
|||
{
|
||||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct pci_dev *pdev = adapter->pdev;
|
||||
unsigned long irq_flags;
|
||||
u16 phy_tmp;
|
||||
|
||||
#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
|
||||
|
||||
/*
|
||||
* Prevent stats update while adapter is being reset, or if the pci
|
||||
|
|
@ -2944,14 +3270,6 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
|
|||
if (pci_channel_offline(pdev))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&adapter->stats_lock, irq_flags);
|
||||
|
||||
/*
|
||||
* these counters are modified from e1000_adjust_tbi_stats,
|
||||
* called from the interrupt context, so they must only
|
||||
* be written while holding adapter->stats_lock
|
||||
*/
|
||||
|
||||
adapter->stats.crcerrs += er32(CRCERRS);
|
||||
adapter->stats.gprc += er32(GPRC);
|
||||
adapter->stats.gorc += er32(GORCL);
|
||||
|
|
@ -2988,7 +3306,8 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
|
|||
|
||||
adapter->stats.algnerrc += er32(ALGNERRC);
|
||||
adapter->stats.rxerrc += er32(RXERRC);
|
||||
adapter->stats.tncrs += er32(TNCRS);
|
||||
if (hw->mac.type != e1000_82574)
|
||||
adapter->stats.tncrs += er32(TNCRS);
|
||||
adapter->stats.cexterr += er32(CEXTERR);
|
||||
adapter->stats.tsctc += er32(TSCTC);
|
||||
adapter->stats.tsctfc += er32(TSCTFC);
|
||||
|
|
@ -3022,21 +3341,10 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
|
|||
|
||||
/* Tx Dropped needs to be maintained elsewhere */
|
||||
|
||||
/* Phy Stats */
|
||||
if (hw->phy.media_type == e1000_media_type_copper) {
|
||||
if ((adapter->link_speed == SPEED_1000) &&
|
||||
(!e1e_rphy(hw, PHY_1000T_STATUS, &phy_tmp))) {
|
||||
phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
|
||||
adapter->phy_stats.idle_errors += phy_tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Management Stats */
|
||||
adapter->stats.mgptc += er32(MGTPTC);
|
||||
adapter->stats.mgprc += er32(MGTPRC);
|
||||
adapter->stats.mgpdc += er32(MGTPDC);
|
||||
|
||||
spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3048,10 +3356,6 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter)
|
|||
struct e1000_hw *hw = &adapter->hw;
|
||||
struct e1000_phy_regs *phy = &adapter->phy_regs;
|
||||
int ret_val;
|
||||
unsigned long irq_flags;
|
||||
|
||||
|
||||
spin_lock_irqsave(&adapter->stats_lock, irq_flags);
|
||||
|
||||
if ((er32(STATUS) & E1000_STATUS_LU) &&
|
||||
(adapter->hw.phy.media_type == e1000_media_type_copper)) {
|
||||
|
|
@ -3082,8 +3386,6 @@ static void e1000_phy_read_status(struct e1000_adapter *adapter)
|
|||
phy->stat1000 = 0;
|
||||
phy->estatus = (ESTATUS_1000_TFULL | ESTATUS_1000_THALF);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&adapter->stats_lock, irq_flags);
|
||||
}
|
||||
|
||||
static void e1000_print_link_info(struct e1000_adapter *adapter)
|
||||
|
|
@ -3200,6 +3502,27 @@ static void e1000_watchdog_task(struct work_struct *work)
|
|||
&adapter->link_speed,
|
||||
&adapter->link_duplex);
|
||||
e1000_print_link_info(adapter);
|
||||
/*
|
||||
* On supported PHYs, check for duplex mismatch only
|
||||
* if link has autonegotiated at 10/100 half
|
||||
*/
|
||||
if ((hw->phy.type == e1000_phy_igp_3 ||
|
||||
hw->phy.type == e1000_phy_bm) &&
|
||||
(hw->mac.autoneg == true) &&
|
||||
(adapter->link_speed == SPEED_10 ||
|
||||
adapter->link_speed == SPEED_100) &&
|
||||
(adapter->link_duplex == HALF_DUPLEX)) {
|
||||
u16 autoneg_exp;
|
||||
|
||||
e1e_rphy(hw, PHY_AUTONEG_EXP, &autoneg_exp);
|
||||
|
||||
if (!(autoneg_exp & NWAY_ER_LP_NWAY_CAPS))
|
||||
e_info("Autonegotiated half duplex but"
|
||||
" link partner cannot autoneg. "
|
||||
" Try forcing full duplex if "
|
||||
"link gets many collisions.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* tweak tx_queue_len according to speed/duplex
|
||||
* and adjust the timeout factor
|
||||
|
|
@ -3315,7 +3638,10 @@ link_up:
|
|||
}
|
||||
|
||||
/* Cause software interrupt to ensure Rx ring is cleaned */
|
||||
ew32(ICS, E1000_ICS_RXDMT0);
|
||||
if (adapter->msix_entries)
|
||||
ew32(ICS, adapter->rx_ring->ims_val);
|
||||
else
|
||||
ew32(ICS, E1000_ICS_RXDMT0);
|
||||
|
||||
/* Force detection of hung controller every watchdog period */
|
||||
adapter->detect_tx_hung = 1;
|
||||
|
|
@ -3423,34 +3749,50 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
|
|||
struct e1000_buffer *buffer_info;
|
||||
unsigned int i;
|
||||
u8 css;
|
||||
u32 cmd_len = E1000_TXD_CMD_DEXT;
|
||||
|
||||
if (skb->ip_summed == CHECKSUM_PARTIAL) {
|
||||
css = skb_transport_offset(skb);
|
||||
if (skb->ip_summed != CHECKSUM_PARTIAL)
|
||||
return 0;
|
||||
|
||||
i = tx_ring->next_to_use;
|
||||
buffer_info = &tx_ring->buffer_info[i];
|
||||
context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
|
||||
|
||||
context_desc->lower_setup.ip_config = 0;
|
||||
context_desc->upper_setup.tcp_fields.tucss = css;
|
||||
context_desc->upper_setup.tcp_fields.tucso =
|
||||
css + skb->csum_offset;
|
||||
context_desc->upper_setup.tcp_fields.tucse = 0;
|
||||
context_desc->tcp_seg_setup.data = 0;
|
||||
context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
|
||||
|
||||
buffer_info->time_stamp = jiffies;
|
||||
buffer_info->next_to_watch = i;
|
||||
|
||||
i++;
|
||||
if (i == tx_ring->count)
|
||||
i = 0;
|
||||
tx_ring->next_to_use = i;
|
||||
|
||||
return 1;
|
||||
switch (skb->protocol) {
|
||||
case __constant_htons(ETH_P_IP):
|
||||
if (ip_hdr(skb)->protocol == IPPROTO_TCP)
|
||||
cmd_len |= E1000_TXD_CMD_TCP;
|
||||
break;
|
||||
case __constant_htons(ETH_P_IPV6):
|
||||
/* XXX not handling all IPV6 headers */
|
||||
if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP)
|
||||
cmd_len |= E1000_TXD_CMD_TCP;
|
||||
break;
|
||||
default:
|
||||
if (unlikely(net_ratelimit()))
|
||||
e_warn("checksum_partial proto=%x!\n", skb->protocol);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
css = skb_transport_offset(skb);
|
||||
|
||||
i = tx_ring->next_to_use;
|
||||
buffer_info = &tx_ring->buffer_info[i];
|
||||
context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
|
||||
|
||||
context_desc->lower_setup.ip_config = 0;
|
||||
context_desc->upper_setup.tcp_fields.tucss = css;
|
||||
context_desc->upper_setup.tcp_fields.tucso =
|
||||
css + skb->csum_offset;
|
||||
context_desc->upper_setup.tcp_fields.tucse = 0;
|
||||
context_desc->tcp_seg_setup.data = 0;
|
||||
context_desc->cmd_and_length = cpu_to_le32(cmd_len);
|
||||
|
||||
buffer_info->time_stamp = jiffies;
|
||||
buffer_info->next_to_watch = i;
|
||||
|
||||
i++;
|
||||
if (i == tx_ring->count)
|
||||
i = 0;
|
||||
tx_ring->next_to_use = i;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define E1000_MAX_PER_TXD 8192
|
||||
|
|
@ -4032,6 +4374,7 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
e1000e_down(adapter);
|
||||
e1000_free_irq(adapter);
|
||||
}
|
||||
e1000e_reset_interrupt_capability(adapter);
|
||||
|
||||
retval = pci_save_state(pdev);
|
||||
if (retval)
|
||||
|
|
@ -4158,6 +4501,7 @@ static int e1000_resume(struct pci_dev *pdev)
|
|||
pci_enable_wake(pdev, PCI_D3hot, 0);
|
||||
pci_enable_wake(pdev, PCI_D3cold, 0);
|
||||
|
||||
e1000e_set_interrupt_capability(adapter);
|
||||
if (netif_running(netdev)) {
|
||||
err = e1000_request_irq(adapter);
|
||||
if (err)
|
||||
|
|
@ -4335,13 +4679,15 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter)
|
|||
ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &buf);
|
||||
if (!(le16_to_cpu(buf) & (1 << 0))) {
|
||||
/* Deep Smart Power Down (DSPD) */
|
||||
e_warn("Warning: detected DSPD enabled in EEPROM\n");
|
||||
dev_warn(&adapter->pdev->dev,
|
||||
"Warning: detected DSPD enabled in EEPROM\n");
|
||||
}
|
||||
|
||||
ret_val = e1000_read_nvm(hw, NVM_INIT_3GIO_3, 1, &buf);
|
||||
if (le16_to_cpu(buf) & (3 << 2)) {
|
||||
/* ASPM enable */
|
||||
e_warn("Warning: detected ASPM enabled in EEPROM\n");
|
||||
dev_warn(&adapter->pdev->dev,
|
||||
"Warning: detected ASPM enabled in EEPROM\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4467,6 +4813,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
|
|||
|
||||
adapter->bd_number = cards_found++;
|
||||
|
||||
e1000e_check_options(adapter);
|
||||
|
||||
/* setup adapter struct */
|
||||
err = e1000_sw_init(adapter);
|
||||
if (err)
|
||||
|
|
@ -4482,6 +4830,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
|
|||
if (err)
|
||||
goto err_hw_init;
|
||||
|
||||
if ((adapter->flags & FLAG_IS_ICH) &&
|
||||
(adapter->flags & FLAG_READ_ONLY_NVM))
|
||||
e1000e_write_protect_nvm_ich8lan(&adapter->hw);
|
||||
|
||||
hw->mac.ops.get_bus_info(&adapter->hw);
|
||||
|
||||
adapter->hw.phy.autoneg_wait_to_complete = 0;
|
||||
|
|
@ -4572,8 +4924,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
|
|||
|
||||
INIT_WORK(&adapter->reset_task, e1000_reset_task);
|
||||
INIT_WORK(&adapter->watchdog_task, e1000_watchdog_task);
|
||||
|
||||
e1000e_check_options(adapter);
|
||||
INIT_WORK(&adapter->downshift_task, e1000e_downshift_workaround);
|
||||
INIT_WORK(&adapter->update_phy_task, e1000e_update_phy_task);
|
||||
|
||||
/* Initialize link parameters. User can change them with ethtool */
|
||||
adapter->hw.mac.autoneg = 1;
|
||||
|
|
@ -4704,6 +5056,7 @@ static void __devexit e1000_remove(struct pci_dev *pdev)
|
|||
if (!e1000_check_reset_block(&adapter->hw))
|
||||
e1000_phy_hw_reset(&adapter->hw);
|
||||
|
||||
e1000e_reset_interrupt_capability(adapter);
|
||||
kfree(adapter->tx_ring);
|
||||
kfree(adapter->rx_ring);
|
||||
|
||||
|
|
@ -4745,6 +5098,8 @@ static struct pci_device_id e1000_pci_tbl[] = {
|
|||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573E_IAMT), board_82573 },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L), board_82574 },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT),
|
||||
board_80003es2lan },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_SPT),
|
||||
|
|
@ -4767,6 +5122,7 @@ static struct pci_device_id e1000_pci_tbl[] = {
|
|||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IFE_GT), board_ich9lan },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_AMT), board_ich9lan },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_C), board_ich9lan },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_BM), board_ich9lan },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M), board_ich9lan },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_AMT), board_ich9lan },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH9_IGP_M_V), board_ich9lan },
|
||||
|
|
@ -4775,6 +5131,9 @@ static struct pci_device_id e1000_pci_tbl[] = {
|
|||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_LF), board_ich9lan },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_R_BM_V), board_ich9lan },
|
||||
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LM), board_ich10lan },
|
||||
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_ICH10_D_BM_LF), board_ich10lan },
|
||||
|
||||
{ } /* terminate list */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
|
||||
|
|
|
|||
|
|
@ -114,6 +114,15 @@ E1000_PARAM(InterruptThrottleRate, "Interrupt Throttling Rate");
|
|||
#define DEFAULT_ITR 3
|
||||
#define MAX_ITR 100000
|
||||
#define MIN_ITR 100
|
||||
/* IntMode (Interrupt Mode)
|
||||
*
|
||||
* Valid Range: 0 - 2
|
||||
*
|
||||
* Default Value: 2 (MSI-X)
|
||||
*/
|
||||
E1000_PARAM(IntMode, "Interrupt Mode");
|
||||
#define MAX_INTMODE 2
|
||||
#define MIN_INTMODE 0
|
||||
|
||||
/*
|
||||
* Enable Smart Power Down of the PHY
|
||||
|
|
@ -133,6 +142,15 @@ E1000_PARAM(SmartPowerDownEnable, "Enable PHY smart power down");
|
|||
*/
|
||||
E1000_PARAM(KumeranLockLoss, "Enable Kumeran lock loss workaround");
|
||||
|
||||
/*
|
||||
* Write Protect NVM
|
||||
*
|
||||
* Valid Range: 0, 1
|
||||
*
|
||||
* Default Value: 1 (enabled)
|
||||
*/
|
||||
E1000_PARAM(WriteProtectNVM, "Write-protect NVM [WARNING: disabling this can lead to corrupted NVM]");
|
||||
|
||||
struct e1000_option {
|
||||
enum { enable_option, range_option, list_option } type;
|
||||
const char *name;
|
||||
|
|
@ -352,6 +370,24 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
|
|||
adapter->itr = 20000;
|
||||
}
|
||||
}
|
||||
{ /* Interrupt Mode */
|
||||
struct e1000_option opt = {
|
||||
.type = range_option,
|
||||
.name = "Interrupt Mode",
|
||||
.err = "defaulting to 2 (MSI-X)",
|
||||
.def = E1000E_INT_MODE_MSIX,
|
||||
.arg = { .r = { .min = MIN_INTMODE,
|
||||
.max = MAX_INTMODE } }
|
||||
};
|
||||
|
||||
if (num_IntMode > bd) {
|
||||
unsigned int int_mode = IntMode[bd];
|
||||
e1000_validate_option(&int_mode, &opt, adapter);
|
||||
adapter->int_mode = int_mode;
|
||||
} else {
|
||||
adapter->int_mode = opt.def;
|
||||
}
|
||||
}
|
||||
{ /* Smart Power Down */
|
||||
const struct e1000_option opt = {
|
||||
.type = enable_option,
|
||||
|
|
@ -388,4 +424,25 @@ void __devinit e1000e_check_options(struct e1000_adapter *adapter)
|
|||
opt.def);
|
||||
}
|
||||
}
|
||||
{ /* Write-protect NVM */
|
||||
const struct e1000_option opt = {
|
||||
.type = enable_option,
|
||||
.name = "Write-protect NVM",
|
||||
.err = "defaulting to Enabled",
|
||||
.def = OPTION_ENABLED
|
||||
};
|
||||
|
||||
if (adapter->flags & FLAG_IS_ICH) {
|
||||
if (num_WriteProtectNVM > bd) {
|
||||
unsigned int write_protect_nvm = WriteProtectNVM[bd];
|
||||
e1000_validate_option(&write_protect_nvm, &opt,
|
||||
adapter);
|
||||
if (write_protect_nvm)
|
||||
adapter->flags |= FLAG_READ_ONLY_NVM;
|
||||
} else {
|
||||
if (opt.def)
|
||||
adapter->flags |= FLAG_READ_ONLY_NVM;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -476,7 +476,9 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
|
|||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
if ((phy->type == e1000_phy_m88) && (phy->revision < 4)) {
|
||||
if ((phy->type == e1000_phy_m88) &&
|
||||
(phy->revision < E1000_REVISION_4) &&
|
||||
(phy->id != BME1000_E_PHY_ID_R2)) {
|
||||
/*
|
||||
* Force TX_CLK in the Extended PHY Specific Control Register
|
||||
* to 25MHz clock.
|
||||
|
|
@ -504,6 +506,18 @@ s32 e1000e_copper_link_setup_m88(struct e1000_hw *hw)
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
if ((phy->type == e1000_phy_bm) && (phy->id == BME1000_E_PHY_ID_R2)) {
|
||||
/* Set PHY page 0, register 29 to 0x0003 */
|
||||
ret_val = e1e_wphy(hw, 29, 0x0003);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
/* Set PHY page 0, register 30 to 0x0000 */
|
||||
ret_val = e1e_wphy(hw, 30, 0x0000);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/* Commit the changes. */
|
||||
ret_val = e1000e_commit_phy(hw);
|
||||
if (ret_val)
|
||||
|
|
@ -1720,6 +1734,91 @@ s32 e1000e_get_cfg_done(struct e1000_hw *hw)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000e_phy_init_script_igp3 - Inits the IGP3 PHY
|
||||
* @hw: pointer to the HW structure
|
||||
*
|
||||
* Initializes a Intel Gigabit PHY3 when an EEPROM is not present.
|
||||
**/
|
||||
s32 e1000e_phy_init_script_igp3(struct e1000_hw *hw)
|
||||
{
|
||||
hw_dbg(hw, "Running IGP 3 PHY init script\n");
|
||||
|
||||
/* PHY init IGP 3 */
|
||||
/* Enable rise/fall, 10-mode work in class-A */
|
||||
e1e_wphy(hw, 0x2F5B, 0x9018);
|
||||
/* Remove all caps from Replica path filter */
|
||||
e1e_wphy(hw, 0x2F52, 0x0000);
|
||||
/* Bias trimming for ADC, AFE and Driver (Default) */
|
||||
e1e_wphy(hw, 0x2FB1, 0x8B24);
|
||||
/* Increase Hybrid poly bias */
|
||||
e1e_wphy(hw, 0x2FB2, 0xF8F0);
|
||||
/* Add 4% to Tx amplitude in Gig mode */
|
||||
e1e_wphy(hw, 0x2010, 0x10B0);
|
||||
/* Disable trimming (TTT) */
|
||||
e1e_wphy(hw, 0x2011, 0x0000);
|
||||
/* Poly DC correction to 94.6% + 2% for all channels */
|
||||
e1e_wphy(hw, 0x20DD, 0x249A);
|
||||
/* ABS DC correction to 95.9% */
|
||||
e1e_wphy(hw, 0x20DE, 0x00D3);
|
||||
/* BG temp curve trim */
|
||||
e1e_wphy(hw, 0x28B4, 0x04CE);
|
||||
/* Increasing ADC OPAMP stage 1 currents to max */
|
||||
e1e_wphy(hw, 0x2F70, 0x29E4);
|
||||
/* Force 1000 ( required for enabling PHY regs configuration) */
|
||||
e1e_wphy(hw, 0x0000, 0x0140);
|
||||
/* Set upd_freq to 6 */
|
||||
e1e_wphy(hw, 0x1F30, 0x1606);
|
||||
/* Disable NPDFE */
|
||||
e1e_wphy(hw, 0x1F31, 0xB814);
|
||||
/* Disable adaptive fixed FFE (Default) */
|
||||
e1e_wphy(hw, 0x1F35, 0x002A);
|
||||
/* Enable FFE hysteresis */
|
||||
e1e_wphy(hw, 0x1F3E, 0x0067);
|
||||
/* Fixed FFE for short cable lengths */
|
||||
e1e_wphy(hw, 0x1F54, 0x0065);
|
||||
/* Fixed FFE for medium cable lengths */
|
||||
e1e_wphy(hw, 0x1F55, 0x002A);
|
||||
/* Fixed FFE for long cable lengths */
|
||||
e1e_wphy(hw, 0x1F56, 0x002A);
|
||||
/* Enable Adaptive Clip Threshold */
|
||||
e1e_wphy(hw, 0x1F72, 0x3FB0);
|
||||
/* AHT reset limit to 1 */
|
||||
e1e_wphy(hw, 0x1F76, 0xC0FF);
|
||||
/* Set AHT master delay to 127 msec */
|
||||
e1e_wphy(hw, 0x1F77, 0x1DEC);
|
||||
/* Set scan bits for AHT */
|
||||
e1e_wphy(hw, 0x1F78, 0xF9EF);
|
||||
/* Set AHT Preset bits */
|
||||
e1e_wphy(hw, 0x1F79, 0x0210);
|
||||
/* Change integ_factor of channel A to 3 */
|
||||
e1e_wphy(hw, 0x1895, 0x0003);
|
||||
/* Change prop_factor of channels BCD to 8 */
|
||||
e1e_wphy(hw, 0x1796, 0x0008);
|
||||
/* Change cg_icount + enable integbp for channels BCD */
|
||||
e1e_wphy(hw, 0x1798, 0xD008);
|
||||
/*
|
||||
* Change cg_icount + enable integbp + change prop_factor_master
|
||||
* to 8 for channel A
|
||||
*/
|
||||
e1e_wphy(hw, 0x1898, 0xD918);
|
||||
/* Disable AHT in Slave mode on channel A */
|
||||
e1e_wphy(hw, 0x187A, 0x0800);
|
||||
/*
|
||||
* Enable LPLU and disable AN to 1000 in non-D0a states,
|
||||
* Enable SPD+B2B
|
||||
*/
|
||||
e1e_wphy(hw, 0x0019, 0x008D);
|
||||
/* Enable restart AN on an1000_dis change */
|
||||
e1e_wphy(hw, 0x001B, 0x2080);
|
||||
/* Enable wh_fifo read clock in 10/100 modes */
|
||||
e1e_wphy(hw, 0x0014, 0x0045);
|
||||
/* Restart AN, Speed selection is 1000 */
|
||||
e1e_wphy(hw, 0x0000, 0x1340);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Internal function pointers */
|
||||
|
||||
/**
|
||||
|
|
@ -1968,6 +2067,99 @@ out:
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000e_read_phy_reg_bm2 - Read BM PHY register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to be read
|
||||
* @data: pointer to the read data
|
||||
*
|
||||
* Acquires semaphore, if necessary, then reads the PHY register at offset
|
||||
* and storing the retrieved information in data. Release any acquired
|
||||
* semaphores before exiting.
|
||||
**/
|
||||
s32 e1000e_read_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 *data)
|
||||
{
|
||||
s32 ret_val;
|
||||
u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
|
||||
|
||||
/* Page 800 works differently than the rest so it has its own func */
|
||||
if (page == BM_WUC_PAGE) {
|
||||
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, data,
|
||||
true);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
ret_val = hw->phy.ops.acquire_phy(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
hw->phy.addr = 1;
|
||||
|
||||
if (offset > MAX_PHY_MULTI_PAGE_REG) {
|
||||
|
||||
/* Page is shifted left, PHY expects (page x 32) */
|
||||
ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
|
||||
page);
|
||||
|
||||
if (ret_val) {
|
||||
hw->phy.ops.release_phy(hw);
|
||||
return ret_val;
|
||||
}
|
||||
}
|
||||
|
||||
ret_val = e1000e_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
|
||||
data);
|
||||
hw->phy.ops.release_phy(hw);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000e_write_phy_reg_bm2 - Write BM PHY register
|
||||
* @hw: pointer to the HW structure
|
||||
* @offset: register offset to write to
|
||||
* @data: data to write at register offset
|
||||
*
|
||||
* Acquires semaphore, if necessary, then writes the data to PHY register
|
||||
* at the offset. Release any acquired semaphores before exiting.
|
||||
**/
|
||||
s32 e1000e_write_phy_reg_bm2(struct e1000_hw *hw, u32 offset, u16 data)
|
||||
{
|
||||
s32 ret_val;
|
||||
u16 page = (u16)(offset >> IGP_PAGE_SHIFT);
|
||||
|
||||
/* Page 800 works differently than the rest so it has its own func */
|
||||
if (page == BM_WUC_PAGE) {
|
||||
ret_val = e1000_access_phy_wakeup_reg_bm(hw, offset, &data,
|
||||
false);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
ret_val = hw->phy.ops.acquire_phy(hw);
|
||||
if (ret_val)
|
||||
return ret_val;
|
||||
|
||||
hw->phy.addr = 1;
|
||||
|
||||
if (offset > MAX_PHY_MULTI_PAGE_REG) {
|
||||
/* Page is shifted left, PHY expects (page x 32) */
|
||||
ret_val = e1000e_write_phy_reg_mdic(hw, BM_PHY_PAGE_SELECT,
|
||||
page);
|
||||
|
||||
if (ret_val) {
|
||||
hw->phy.ops.release_phy(hw);
|
||||
return ret_val;
|
||||
}
|
||||
}
|
||||
|
||||
ret_val = e1000e_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset,
|
||||
data);
|
||||
|
||||
hw->phy.ops.release_phy(hw);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* e1000_access_phy_wakeup_reg_bm - Read BM PHY wakeup register
|
||||
* @hw: pointer to the HW structure
|
||||
|
|
|
|||
|
|
@ -40,13 +40,13 @@
|
|||
#include <asm/io.h>
|
||||
|
||||
#define DRV_NAME "ehea"
|
||||
#define DRV_VERSION "EHEA_0092"
|
||||
#define DRV_VERSION "EHEA_0093"
|
||||
|
||||
/* eHEA capability flags */
|
||||
#define DLPAR_PORT_ADD_REM 1
|
||||
#define DLPAR_MEM_ADD 2
|
||||
#define DLPAR_MEM_REM 4
|
||||
#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD)
|
||||
#define EHEA_CAPABILITIES (DLPAR_PORT_ADD_REM | DLPAR_MEM_ADD | DLPAR_MEM_REM)
|
||||
|
||||
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
|
||||
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
|
||||
|
|
|
|||
|
|
@ -535,7 +535,7 @@ u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr)
|
|||
cb_logaddr, /* R5 */
|
||||
0, 0, 0, 0, 0); /* R6-R10 */
|
||||
#ifdef DEBUG
|
||||
ehea_dmp(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea");
|
||||
ehea_dump(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea");
|
||||
#endif
|
||||
return hret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -595,7 +595,8 @@ static int ehea_create_busmap_callback(unsigned long pfn,
|
|||
end_section = start_section + ((nr_pages * PAGE_SIZE) / EHEA_SECTSIZE);
|
||||
mr_len = *(unsigned long *)arg;
|
||||
|
||||
ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL);
|
||||
if (!ehea_bmap)
|
||||
ehea_bmap = kzalloc(sizeof(struct ehea_bmap), GFP_KERNEL);
|
||||
if (!ehea_bmap)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ spi_read_buf(struct enc28j60_net *priv, int len, u8 *data)
|
|||
}
|
||||
if (ret && netif_msg_drv(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
|
||||
__FUNCTION__, ret);
|
||||
__func__, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -131,7 +131,7 @@ static int spi_write_buf(struct enc28j60_net *priv, int len,
|
|||
ret = spi_write(priv->spi, priv->spi_transfer_buf, len + 1);
|
||||
if (ret && netif_msg_drv(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
|
||||
__FUNCTION__, ret);
|
||||
__func__, ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -156,7 +156,7 @@ static u8 spi_read_op(struct enc28j60_net *priv, u8 op,
|
|||
ret = spi_write_then_read(priv->spi, tx_buf, 1, rx_buf, slen);
|
||||
if (ret)
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
|
||||
__FUNCTION__, ret);
|
||||
__func__, ret);
|
||||
else
|
||||
val = rx_buf[slen - 1];
|
||||
|
||||
|
|
@ -176,14 +176,14 @@ static int spi_write_op(struct enc28j60_net *priv, u8 op,
|
|||
ret = spi_write(priv->spi, priv->spi_transfer_buf, 2);
|
||||
if (ret && netif_msg_drv(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() failed: ret = %d\n",
|
||||
__FUNCTION__, ret);
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void enc28j60_soft_reset(struct enc28j60_net *priv)
|
||||
{
|
||||
if (netif_msg_hw(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
|
||||
|
||||
spi_write_op(priv, ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET);
|
||||
/* Errata workaround #1, CLKRDY check is unreliable,
|
||||
|
|
@ -357,7 +357,7 @@ static void enc28j60_mem_read(struct enc28j60_net *priv,
|
|||
reg = nolock_regw_read(priv, ERDPTL);
|
||||
if (reg != addr)
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() error writing ERDPT "
|
||||
"(0x%04x - 0x%04x)\n", __FUNCTION__, reg, addr);
|
||||
"(0x%04x - 0x%04x)\n", __func__, reg, addr);
|
||||
}
|
||||
#endif
|
||||
spi_read_buf(priv, len, data);
|
||||
|
|
@ -380,7 +380,7 @@ enc28j60_packet_write(struct enc28j60_net *priv, int len, const u8 *data)
|
|||
if (reg != TXSTART_INIT)
|
||||
printk(KERN_DEBUG DRV_NAME
|
||||
": %s() ERWPT:0x%04x != 0x%04x\n",
|
||||
__FUNCTION__, reg, TXSTART_INIT);
|
||||
__func__, reg, TXSTART_INIT);
|
||||
}
|
||||
#endif
|
||||
/* Set the TXND pointer to correspond to the packet size given */
|
||||
|
|
@ -390,13 +390,13 @@ enc28j60_packet_write(struct enc28j60_net *priv, int len, const u8 *data)
|
|||
if (netif_msg_hw(priv))
|
||||
printk(KERN_DEBUG DRV_NAME
|
||||
": %s() after control byte ERWPT:0x%04x\n",
|
||||
__FUNCTION__, nolock_regw_read(priv, EWRPTL));
|
||||
__func__, nolock_regw_read(priv, EWRPTL));
|
||||
/* copy the packet into the transmit buffer */
|
||||
spi_write_buf(priv, len, data);
|
||||
if (netif_msg_hw(priv))
|
||||
printk(KERN_DEBUG DRV_NAME
|
||||
": %s() after write packet ERWPT:0x%04x, len=%d\n",
|
||||
__FUNCTION__, nolock_regw_read(priv, EWRPTL), len);
|
||||
__func__, nolock_regw_read(priv, EWRPTL), len);
|
||||
mutex_unlock(&priv->lock);
|
||||
}
|
||||
|
||||
|
|
@ -495,7 +495,7 @@ static int enc28j60_set_hw_macaddr(struct net_device *ndev)
|
|||
if (netif_msg_drv(priv))
|
||||
printk(KERN_DEBUG DRV_NAME
|
||||
": %s() Hardware must be disabled to set "
|
||||
"Mac address\n", __FUNCTION__);
|
||||
"Mac address\n", __func__);
|
||||
ret = -EBUSY;
|
||||
}
|
||||
mutex_unlock(&priv->lock);
|
||||
|
|
@ -575,7 +575,7 @@ static void nolock_rxfifo_init(struct enc28j60_net *priv, u16 start, u16 end)
|
|||
if (start > 0x1FFF || end > 0x1FFF || start > end) {
|
||||
if (netif_msg_drv(priv))
|
||||
printk(KERN_ERR DRV_NAME ": %s(%d, %d) RXFIFO "
|
||||
"bad parameters!\n", __FUNCTION__, start, end);
|
||||
"bad parameters!\n", __func__, start, end);
|
||||
return;
|
||||
}
|
||||
/* set receive buffer start + end */
|
||||
|
|
@ -591,7 +591,7 @@ static void nolock_txfifo_init(struct enc28j60_net *priv, u16 start, u16 end)
|
|||
if (start > 0x1FFF || end > 0x1FFF || start > end) {
|
||||
if (netif_msg_drv(priv))
|
||||
printk(KERN_ERR DRV_NAME ": %s(%d, %d) TXFIFO "
|
||||
"bad parameters!\n", __FUNCTION__, start, end);
|
||||
"bad parameters!\n", __func__, start, end);
|
||||
return;
|
||||
}
|
||||
/* set transmit buffer start + end */
|
||||
|
|
@ -630,7 +630,7 @@ static int enc28j60_hw_init(struct enc28j60_net *priv)
|
|||
u8 reg;
|
||||
|
||||
if (netif_msg_drv(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() - %s\n", __FUNCTION__,
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() - %s\n", __func__,
|
||||
priv->full_duplex ? "FullDuplex" : "HalfDuplex");
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
|
@ -661,7 +661,7 @@ static int enc28j60_hw_init(struct enc28j60_net *priv)
|
|||
if (reg == 0x00 || reg == 0xff) {
|
||||
if (netif_msg_drv(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() Invalid RevId %d\n",
|
||||
__FUNCTION__, reg);
|
||||
__func__, reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -724,7 +724,7 @@ static void enc28j60_hw_enable(struct enc28j60_net *priv)
|
|||
/* enable interrupts */
|
||||
if (netif_msg_hw(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() enabling interrupts.\n",
|
||||
__FUNCTION__);
|
||||
__func__);
|
||||
|
||||
enc28j60_phy_write(priv, PHIE, PHIE_PGEIE | PHIE_PLNKIE);
|
||||
|
||||
|
|
@ -888,7 +888,7 @@ static void enc28j60_hw_rx(struct net_device *ndev)
|
|||
if (netif_msg_rx_err(priv))
|
||||
dev_err(&ndev->dev,
|
||||
"%s() Invalid packet address!! 0x%04x\n",
|
||||
__FUNCTION__, priv->next_pk_ptr);
|
||||
__func__, priv->next_pk_ptr);
|
||||
/* packet address corrupted: reset RX logic */
|
||||
mutex_lock(&priv->lock);
|
||||
nolock_reg_bfclr(priv, ECON1, ECON1_RXEN);
|
||||
|
|
@ -917,7 +917,7 @@ static void enc28j60_hw_rx(struct net_device *ndev)
|
|||
rxstat |= rsv[4];
|
||||
|
||||
if (netif_msg_rx_status(priv))
|
||||
enc28j60_dump_rsv(priv, __FUNCTION__, next_packet, len, rxstat);
|
||||
enc28j60_dump_rsv(priv, __func__, next_packet, len, rxstat);
|
||||
|
||||
if (!RSV_GETBIT(rxstat, RSV_RXOK)) {
|
||||
if (netif_msg_rx_err(priv))
|
||||
|
|
@ -941,7 +941,7 @@ static void enc28j60_hw_rx(struct net_device *ndev)
|
|||
enc28j60_mem_read(priv, priv->next_pk_ptr + sizeof(rsv),
|
||||
len, skb_put(skb, len));
|
||||
if (netif_msg_pktdata(priv))
|
||||
dump_packet(__FUNCTION__, skb->len, skb->data);
|
||||
dump_packet(__func__, skb->len, skb->data);
|
||||
skb->protocol = eth_type_trans(skb, ndev);
|
||||
/* update statistics */
|
||||
ndev->stats.rx_packets++;
|
||||
|
|
@ -958,7 +958,7 @@ static void enc28j60_hw_rx(struct net_device *ndev)
|
|||
erxrdpt = erxrdpt_workaround(next_packet, RXSTART_INIT, RXEND_INIT);
|
||||
if (netif_msg_hw(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT:0x%04x\n",
|
||||
__FUNCTION__, erxrdpt);
|
||||
__func__, erxrdpt);
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
nolock_regw_write(priv, ERXRDPTL, erxrdpt);
|
||||
|
|
@ -968,7 +968,7 @@ static void enc28j60_hw_rx(struct net_device *ndev)
|
|||
reg = nolock_regw_read(priv, ERXRDPTL);
|
||||
if (reg != erxrdpt)
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() ERXRDPT verify "
|
||||
"error (0x%04x - 0x%04x)\n", __FUNCTION__,
|
||||
"error (0x%04x - 0x%04x)\n", __func__,
|
||||
reg, erxrdpt);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1006,7 +1006,7 @@ static int enc28j60_get_free_rxfifo(struct enc28j60_net *priv)
|
|||
mutex_unlock(&priv->lock);
|
||||
if (netif_msg_rx_status(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() free_space = %d\n",
|
||||
__FUNCTION__, free_space);
|
||||
__func__, free_space);
|
||||
return free_space;
|
||||
}
|
||||
|
||||
|
|
@ -1022,7 +1022,7 @@ static void enc28j60_check_link_status(struct net_device *ndev)
|
|||
reg = enc28j60_phy_read(priv, PHSTAT2);
|
||||
if (netif_msg_hw(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() PHSTAT1: %04x, "
|
||||
"PHSTAT2: %04x\n", __FUNCTION__,
|
||||
"PHSTAT2: %04x\n", __func__,
|
||||
enc28j60_phy_read(priv, PHSTAT1), reg);
|
||||
duplex = reg & PHSTAT2_DPXSTAT;
|
||||
|
||||
|
|
@ -1095,7 +1095,7 @@ static void enc28j60_irq_work_handler(struct work_struct *work)
|
|||
int intflags, loop;
|
||||
|
||||
if (netif_msg_intr(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
|
||||
/* disable further interrupts */
|
||||
locked_reg_bfclr(priv, EIE, EIE_INTIE);
|
||||
|
||||
|
|
@ -1198,7 +1198,7 @@ static void enc28j60_irq_work_handler(struct work_struct *work)
|
|||
/* re-enable interrupts */
|
||||
locked_reg_bfset(priv, EIE, EIE_INTIE);
|
||||
if (netif_msg_intr(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() exit\n", __FUNCTION__);
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() exit\n", __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1213,7 +1213,7 @@ static void enc28j60_hw_tx(struct enc28j60_net *priv)
|
|||
": Tx Packet Len:%d\n", priv->tx_skb->len);
|
||||
|
||||
if (netif_msg_pktdata(priv))
|
||||
dump_packet(__FUNCTION__,
|
||||
dump_packet(__func__,
|
||||
priv->tx_skb->len, priv->tx_skb->data);
|
||||
enc28j60_packet_write(priv, priv->tx_skb->len, priv->tx_skb->data);
|
||||
|
||||
|
|
@ -1254,7 +1254,7 @@ static int enc28j60_send_packet(struct sk_buff *skb, struct net_device *dev)
|
|||
struct enc28j60_net *priv = netdev_priv(dev);
|
||||
|
||||
if (netif_msg_tx_queued(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
|
||||
|
||||
/* If some error occurs while trying to transmit this
|
||||
* packet, you should return '1' from this function.
|
||||
|
|
@ -1325,7 +1325,7 @@ static int enc28j60_net_open(struct net_device *dev)
|
|||
struct enc28j60_net *priv = netdev_priv(dev);
|
||||
|
||||
if (netif_msg_drv(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
|
||||
|
||||
if (!is_valid_ether_addr(dev->dev_addr)) {
|
||||
if (netif_msg_ifup(priv)) {
|
||||
|
|
@ -1363,7 +1363,7 @@ static int enc28j60_net_close(struct net_device *dev)
|
|||
struct enc28j60_net *priv = netdev_priv(dev);
|
||||
|
||||
if (netif_msg_drv(priv))
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __FUNCTION__);
|
||||
printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__);
|
||||
|
||||
enc28j60_hw_disable(priv);
|
||||
enc28j60_lowpower(priv, true);
|
||||
|
|
|
|||
5
drivers/net/enic/Makefile
Normal file
5
drivers/net/enic/Makefile
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
obj-$(CONFIG_ENIC) := enic.o
|
||||
|
||||
enic-y := enic_main.o vnic_cq.o vnic_intr.o vnic_wq.o \
|
||||
enic_res.o vnic_dev.o vnic_rq.o
|
||||
|
||||
79
drivers/net/enic/cq_desc.h
Normal file
79
drivers/net/enic/cq_desc.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CQ_DESC_H_
|
||||
#define _CQ_DESC_H_
|
||||
|
||||
/*
|
||||
* Completion queue descriptor types
|
||||
*/
|
||||
enum cq_desc_types {
|
||||
CQ_DESC_TYPE_WQ_ENET = 0,
|
||||
CQ_DESC_TYPE_DESC_COPY = 1,
|
||||
CQ_DESC_TYPE_WQ_EXCH = 2,
|
||||
CQ_DESC_TYPE_RQ_ENET = 3,
|
||||
CQ_DESC_TYPE_RQ_FCP = 4,
|
||||
};
|
||||
|
||||
/* Completion queue descriptor: 16B
|
||||
*
|
||||
* All completion queues have this basic layout. The
|
||||
* type_specfic area is unique for each completion
|
||||
* queue type.
|
||||
*/
|
||||
struct cq_desc {
|
||||
__le16 completed_index;
|
||||
__le16 q_number;
|
||||
u8 type_specfic[11];
|
||||
u8 type_color;
|
||||
};
|
||||
|
||||
#define CQ_DESC_TYPE_BITS 7
|
||||
#define CQ_DESC_TYPE_MASK ((1 << CQ_DESC_TYPE_BITS) - 1)
|
||||
#define CQ_DESC_COLOR_MASK 1
|
||||
#define CQ_DESC_Q_NUM_BITS 10
|
||||
#define CQ_DESC_Q_NUM_MASK ((1 << CQ_DESC_Q_NUM_BITS) - 1)
|
||||
#define CQ_DESC_COMP_NDX_BITS 12
|
||||
#define CQ_DESC_COMP_NDX_MASK ((1 << CQ_DESC_COMP_NDX_BITS) - 1)
|
||||
|
||||
static inline void cq_desc_dec(const struct cq_desc *desc_arg,
|
||||
u8 *type, u8 *color, u16 *q_number, u16 *completed_index)
|
||||
{
|
||||
const struct cq_desc *desc = desc_arg;
|
||||
const u8 type_color = desc->type_color;
|
||||
|
||||
*color = (type_color >> CQ_DESC_TYPE_BITS) & CQ_DESC_COLOR_MASK;
|
||||
|
||||
/*
|
||||
* Make sure color bit is read from desc *before* other fields
|
||||
* are read from desc. Hardware guarantees color bit is last
|
||||
* bit (byte) written. Adding the rmb() prevents the compiler
|
||||
* and/or CPU from reordering the reads which would potentially
|
||||
* result in reading stale values.
|
||||
*/
|
||||
|
||||
rmb();
|
||||
|
||||
*type = type_color & CQ_DESC_TYPE_MASK;
|
||||
*q_number = le16_to_cpu(desc->q_number) & CQ_DESC_Q_NUM_MASK;
|
||||
*completed_index = le16_to_cpu(desc->completed_index) &
|
||||
CQ_DESC_COMP_NDX_MASK;
|
||||
}
|
||||
|
||||
#endif /* _CQ_DESC_H_ */
|
||||
169
drivers/net/enic/cq_enet_desc.h
Normal file
169
drivers/net/enic/cq_enet_desc.h
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _CQ_ENET_DESC_H_
|
||||
#define _CQ_ENET_DESC_H_
|
||||
|
||||
#include "cq_desc.h"
|
||||
|
||||
/* Ethernet completion queue descriptor: 16B */
|
||||
struct cq_enet_wq_desc {
|
||||
__le16 completed_index;
|
||||
__le16 q_number;
|
||||
u8 reserved[11];
|
||||
u8 type_color;
|
||||
};
|
||||
|
||||
static inline void cq_enet_wq_desc_dec(struct cq_enet_wq_desc *desc,
|
||||
u8 *type, u8 *color, u16 *q_number, u16 *completed_index)
|
||||
{
|
||||
cq_desc_dec((struct cq_desc *)desc, type,
|
||||
color, q_number, completed_index);
|
||||
}
|
||||
|
||||
/* Completion queue descriptor: Ethernet receive queue, 16B */
|
||||
struct cq_enet_rq_desc {
|
||||
__le16 completed_index_flags;
|
||||
__le16 q_number_rss_type_flags;
|
||||
__le32 rss_hash;
|
||||
__le16 bytes_written_flags;
|
||||
__le16 vlan;
|
||||
__le16 checksum_fcoe;
|
||||
u8 flags;
|
||||
u8 type_color;
|
||||
};
|
||||
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT (0x1 << 12)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_FCOE (0x1 << 13)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_EOP (0x1 << 14)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_SOP (0x1 << 15)
|
||||
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_BITS 4
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_MASK \
|
||||
((1 << CQ_ENET_RQ_DESC_RSS_TYPE_BITS) - 1)
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_NONE 0
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv4 1
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv4 2
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6 3
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6 4
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6_EX 5
|
||||
#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6_EX 6
|
||||
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC (0x1 << 14)
|
||||
|
||||
#define CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS 14
|
||||
#define CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK \
|
||||
((1 << CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS) - 1)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_TRUNCATED (0x1 << 14)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED (0x1 << 15)
|
||||
|
||||
#define CQ_ENET_RQ_DESC_FCOE_SOF_BITS 4
|
||||
#define CQ_ENET_RQ_DESC_FCOE_SOF_MASK \
|
||||
((1 << CQ_ENET_RQ_DESC_FCOE_SOF_BITS) - 1)
|
||||
#define CQ_ENET_RQ_DESC_FCOE_EOF_BITS 8
|
||||
#define CQ_ENET_RQ_DESC_FCOE_EOF_MASK \
|
||||
((1 << CQ_ENET_RQ_DESC_FCOE_EOF_BITS) - 1)
|
||||
#define CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT 8
|
||||
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK (0x1 << 0)
|
||||
#define CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK (0x1 << 0)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_UDP (0x1 << 1)
|
||||
#define CQ_ENET_RQ_DESC_FCOE_ENC_ERROR (0x1 << 1)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_TCP (0x1 << 2)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK (0x1 << 3)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_IPV6 (0x1 << 4)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_IPV4 (0x1 << 5)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT (0x1 << 6)
|
||||
#define CQ_ENET_RQ_DESC_FLAGS_FCS_OK (0x1 << 7)
|
||||
|
||||
static inline void cq_enet_rq_desc_dec(struct cq_enet_rq_desc *desc,
|
||||
u8 *type, u8 *color, u16 *q_number, u16 *completed_index,
|
||||
u8 *ingress_port, u8 *fcoe, u8 *eop, u8 *sop, u8 *rss_type,
|
||||
u8 *csum_not_calc, u32 *rss_hash, u16 *bytes_written, u8 *packet_error,
|
||||
u8 *vlan_stripped, u16 *vlan, u16 *checksum, u8 *fcoe_sof,
|
||||
u8 *fcoe_fc_crc_ok, u8 *fcoe_enc_error, u8 *fcoe_eof,
|
||||
u8 *tcp_udp_csum_ok, u8 *udp, u8 *tcp, u8 *ipv4_csum_ok,
|
||||
u8 *ipv6, u8 *ipv4, u8 *ipv4_fragment, u8 *fcs_ok)
|
||||
{
|
||||
u16 completed_index_flags = le16_to_cpu(desc->completed_index_flags);
|
||||
u16 q_number_rss_type_flags =
|
||||
le16_to_cpu(desc->q_number_rss_type_flags);
|
||||
u16 bytes_written_flags = le16_to_cpu(desc->bytes_written_flags);
|
||||
|
||||
cq_desc_dec((struct cq_desc *)desc, type,
|
||||
color, q_number, completed_index);
|
||||
|
||||
*ingress_port = (completed_index_flags &
|
||||
CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT) ? 1 : 0;
|
||||
*fcoe = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_FCOE) ?
|
||||
1 : 0;
|
||||
*eop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_EOP) ?
|
||||
1 : 0;
|
||||
*sop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_SOP) ?
|
||||
1 : 0;
|
||||
|
||||
*rss_type = (u8)((q_number_rss_type_flags >> CQ_DESC_Q_NUM_BITS) &
|
||||
CQ_ENET_RQ_DESC_RSS_TYPE_MASK);
|
||||
*csum_not_calc = (q_number_rss_type_flags &
|
||||
CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC) ? 1 : 0;
|
||||
|
||||
*rss_hash = le32_to_cpu(desc->rss_hash);
|
||||
|
||||
*bytes_written = bytes_written_flags &
|
||||
CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK;
|
||||
*packet_error = (bytes_written_flags &
|
||||
CQ_ENET_RQ_DESC_FLAGS_TRUNCATED) ? 1 : 0;
|
||||
*vlan_stripped = (bytes_written_flags &
|
||||
CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED) ? 1 : 0;
|
||||
|
||||
*vlan = le16_to_cpu(desc->vlan);
|
||||
|
||||
if (*fcoe) {
|
||||
*fcoe_sof = (u8)(le16_to_cpu(desc->checksum_fcoe) &
|
||||
CQ_ENET_RQ_DESC_FCOE_SOF_MASK);
|
||||
*fcoe_fc_crc_ok = (desc->flags &
|
||||
CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK) ? 1 : 0;
|
||||
*fcoe_enc_error = (desc->flags &
|
||||
CQ_ENET_RQ_DESC_FCOE_ENC_ERROR) ? 1 : 0;
|
||||
*fcoe_eof = (u8)((desc->checksum_fcoe >>
|
||||
CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT) &
|
||||
CQ_ENET_RQ_DESC_FCOE_EOF_MASK);
|
||||
*checksum = 0;
|
||||
} else {
|
||||
*fcoe_sof = 0;
|
||||
*fcoe_fc_crc_ok = 0;
|
||||
*fcoe_enc_error = 0;
|
||||
*fcoe_eof = 0;
|
||||
*checksum = le16_to_cpu(desc->checksum_fcoe);
|
||||
}
|
||||
|
||||
*tcp_udp_csum_ok =
|
||||
(desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK) ? 1 : 0;
|
||||
*udp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_UDP) ? 1 : 0;
|
||||
*tcp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP) ? 1 : 0;
|
||||
*ipv4_csum_ok =
|
||||
(desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK) ? 1 : 0;
|
||||
*ipv6 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV6) ? 1 : 0;
|
||||
*ipv4 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4) ? 1 : 0;
|
||||
*ipv4_fragment =
|
||||
(desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT) ? 1 : 0;
|
||||
*fcs_ok = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_FCS_OK) ? 1 : 0;
|
||||
}
|
||||
|
||||
#endif /* _CQ_ENET_DESC_H_ */
|
||||
114
drivers/net/enic/enic.h
Normal file
114
drivers/net/enic/enic.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ENIC_H_
|
||||
#define _ENIC_H_
|
||||
|
||||
#include <linux/inet_lro.h>
|
||||
|
||||
#include "vnic_enet.h"
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_wq.h"
|
||||
#include "vnic_rq.h"
|
||||
#include "vnic_cq.h"
|
||||
#include "vnic_intr.h"
|
||||
#include "vnic_stats.h"
|
||||
#include "vnic_rss.h"
|
||||
|
||||
#define DRV_NAME "enic"
|
||||
#define DRV_DESCRIPTION "Cisco 10G Ethernet Driver"
|
||||
#define DRV_VERSION "0.0.1-18163.472-k1"
|
||||
#define DRV_COPYRIGHT "Copyright 2008 Cisco Systems, Inc"
|
||||
#define PFX DRV_NAME ": "
|
||||
|
||||
#define ENIC_LRO_MAX_DESC 8
|
||||
#define ENIC_LRO_MAX_AGGR 64
|
||||
|
||||
enum enic_cq_index {
|
||||
ENIC_CQ_RQ,
|
||||
ENIC_CQ_WQ,
|
||||
ENIC_CQ_MAX,
|
||||
};
|
||||
|
||||
enum enic_intx_intr_index {
|
||||
ENIC_INTX_WQ_RQ,
|
||||
ENIC_INTX_ERR,
|
||||
ENIC_INTX_NOTIFY,
|
||||
ENIC_INTX_MAX,
|
||||
};
|
||||
|
||||
enum enic_msix_intr_index {
|
||||
ENIC_MSIX_RQ,
|
||||
ENIC_MSIX_WQ,
|
||||
ENIC_MSIX_ERR,
|
||||
ENIC_MSIX_NOTIFY,
|
||||
ENIC_MSIX_MAX,
|
||||
};
|
||||
|
||||
struct enic_msix_entry {
|
||||
int requested;
|
||||
char devname[IFNAMSIZ];
|
||||
irqreturn_t (*isr)(int, void *);
|
||||
void *devid;
|
||||
};
|
||||
|
||||
/* Per-instance private data structure */
|
||||
struct enic {
|
||||
struct net_device *netdev;
|
||||
struct pci_dev *pdev;
|
||||
struct vnic_enet_config config;
|
||||
struct vnic_dev_bar bar0;
|
||||
struct vnic_dev *vdev;
|
||||
struct timer_list notify_timer;
|
||||
struct work_struct reset;
|
||||
struct msix_entry msix_entry[ENIC_MSIX_MAX];
|
||||
struct enic_msix_entry msix[ENIC_MSIX_MAX];
|
||||
u32 msg_enable;
|
||||
spinlock_t devcmd_lock;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
u8 mc_addr[ENIC_MULTICAST_PERFECT_FILTERS][ETH_ALEN];
|
||||
unsigned int mc_count;
|
||||
int csum_rx_enabled;
|
||||
u32 port_mtu;
|
||||
|
||||
/* work queue cache line section */
|
||||
____cacheline_aligned struct vnic_wq wq[1];
|
||||
spinlock_t wq_lock[1];
|
||||
unsigned int wq_count;
|
||||
struct vlan_group *vlan_group;
|
||||
|
||||
/* receive queue cache line section */
|
||||
____cacheline_aligned struct vnic_rq rq[1];
|
||||
unsigned int rq_count;
|
||||
int (*rq_alloc_buf)(struct vnic_rq *rq);
|
||||
struct napi_struct napi;
|
||||
struct net_lro_mgr lro_mgr;
|
||||
struct net_lro_desc lro_desc[ENIC_LRO_MAX_DESC];
|
||||
|
||||
/* interrupt resource cache line section */
|
||||
____cacheline_aligned struct vnic_intr intr[ENIC_MSIX_MAX];
|
||||
unsigned int intr_count;
|
||||
u32 __iomem *legacy_pba; /* memory-mapped */
|
||||
|
||||
/* completion queue cache line section */
|
||||
____cacheline_aligned struct vnic_cq cq[ENIC_CQ_MAX];
|
||||
unsigned int cq_count;
|
||||
};
|
||||
|
||||
#endif /* _ENIC_H_ */
|
||||
1934
drivers/net/enic/enic_main.c
Normal file
1934
drivers/net/enic/enic_main.c
Normal file
File diff suppressed because it is too large
Load diff
370
drivers/net/enic/enic_res.c
Normal file
370
drivers/net/enic/enic_res.c
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "wq_enet_desc.h"
|
||||
#include "rq_enet_desc.h"
|
||||
#include "cq_enet_desc.h"
|
||||
#include "vnic_resource.h"
|
||||
#include "vnic_enet.h"
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_wq.h"
|
||||
#include "vnic_rq.h"
|
||||
#include "vnic_cq.h"
|
||||
#include "vnic_intr.h"
|
||||
#include "vnic_stats.h"
|
||||
#include "vnic_nic.h"
|
||||
#include "vnic_rss.h"
|
||||
#include "enic_res.h"
|
||||
#include "enic.h"
|
||||
|
||||
int enic_get_vnic_config(struct enic *enic)
|
||||
{
|
||||
struct vnic_enet_config *c = &enic->config;
|
||||
int err;
|
||||
|
||||
err = vnic_dev_mac_addr(enic->vdev, enic->mac_addr);
|
||||
if (err) {
|
||||
printk(KERN_ERR PFX "Error getting MAC addr, %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
#define GET_CONFIG(m) \
|
||||
do { \
|
||||
err = vnic_dev_spec(enic->vdev, \
|
||||
offsetof(struct vnic_enet_config, m), \
|
||||
sizeof(c->m), &c->m); \
|
||||
if (err) { \
|
||||
printk(KERN_ERR PFX \
|
||||
"Error getting %s, %d\n", #m, err); \
|
||||
return err; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
GET_CONFIG(flags);
|
||||
GET_CONFIG(wq_desc_count);
|
||||
GET_CONFIG(rq_desc_count);
|
||||
GET_CONFIG(mtu);
|
||||
GET_CONFIG(intr_timer);
|
||||
GET_CONFIG(intr_timer_type);
|
||||
GET_CONFIG(intr_mode);
|
||||
|
||||
c->wq_desc_count =
|
||||
min_t(u32, ENIC_MAX_WQ_DESCS,
|
||||
max_t(u32, ENIC_MIN_WQ_DESCS,
|
||||
c->wq_desc_count));
|
||||
c->wq_desc_count &= 0xfffffff0; /* must be aligned to groups of 16 */
|
||||
|
||||
c->rq_desc_count =
|
||||
min_t(u32, ENIC_MAX_RQ_DESCS,
|
||||
max_t(u32, ENIC_MIN_RQ_DESCS,
|
||||
c->rq_desc_count));
|
||||
c->rq_desc_count &= 0xfffffff0; /* must be aligned to groups of 16 */
|
||||
|
||||
if (c->mtu == 0)
|
||||
c->mtu = 1500;
|
||||
c->mtu = min_t(u16, ENIC_MAX_MTU,
|
||||
max_t(u16, ENIC_MIN_MTU,
|
||||
c->mtu));
|
||||
|
||||
c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer);
|
||||
|
||||
printk(KERN_INFO PFX "vNIC MAC addr %02x:%02x:%02x:%02x:%02x:%02x "
|
||||
"wq/rq %d/%d\n",
|
||||
enic->mac_addr[0], enic->mac_addr[1], enic->mac_addr[2],
|
||||
enic->mac_addr[3], enic->mac_addr[4], enic->mac_addr[5],
|
||||
c->wq_desc_count, c->rq_desc_count);
|
||||
printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d "
|
||||
"intr timer %d\n",
|
||||
c->mtu, ENIC_SETTING(enic, TXCSUM),
|
||||
ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO),
|
||||
ENIC_SETTING(enic, LRO), c->intr_timer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enic_add_station_addr(struct enic *enic)
|
||||
{
|
||||
vnic_dev_add_addr(enic->vdev, enic->mac_addr);
|
||||
}
|
||||
|
||||
void enic_add_multicast_addr(struct enic *enic, u8 *addr)
|
||||
{
|
||||
vnic_dev_add_addr(enic->vdev, addr);
|
||||
}
|
||||
|
||||
void enic_del_multicast_addr(struct enic *enic, u8 *addr)
|
||||
{
|
||||
vnic_dev_del_addr(enic->vdev, addr);
|
||||
}
|
||||
|
||||
void enic_add_vlan(struct enic *enic, u16 vlanid)
|
||||
{
|
||||
u64 a0 = vlanid, a1 = 0;
|
||||
int wait = 1000;
|
||||
int err;
|
||||
|
||||
err = vnic_dev_cmd(enic->vdev, CMD_VLAN_ADD, &a0, &a1, wait);
|
||||
if (err)
|
||||
printk(KERN_ERR PFX "Can't add vlan id, %d\n", err);
|
||||
}
|
||||
|
||||
void enic_del_vlan(struct enic *enic, u16 vlanid)
|
||||
{
|
||||
u64 a0 = vlanid, a1 = 0;
|
||||
int wait = 1000;
|
||||
int err;
|
||||
|
||||
err = vnic_dev_cmd(enic->vdev, CMD_VLAN_DEL, &a0, &a1, wait);
|
||||
if (err)
|
||||
printk(KERN_ERR PFX "Can't delete vlan id, %d\n", err);
|
||||
}
|
||||
|
||||
int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
|
||||
u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
|
||||
u8 ig_vlan_strip_en)
|
||||
{
|
||||
u64 a0, a1;
|
||||
u32 nic_cfg;
|
||||
int wait = 1000;
|
||||
|
||||
vnic_set_nic_cfg(&nic_cfg, rss_default_cpu,
|
||||
rss_hash_type, rss_hash_bits, rss_base_cpu,
|
||||
rss_enable, tso_ipid_split_en, ig_vlan_strip_en);
|
||||
|
||||
a0 = nic_cfg;
|
||||
a1 = 0;
|
||||
|
||||
return vnic_dev_cmd(enic->vdev, CMD_NIC_CFG, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
void enic_free_vnic_resources(struct enic *enic)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < enic->wq_count; i++)
|
||||
vnic_wq_free(&enic->wq[i]);
|
||||
for (i = 0; i < enic->rq_count; i++)
|
||||
vnic_rq_free(&enic->rq[i]);
|
||||
for (i = 0; i < enic->cq_count; i++)
|
||||
vnic_cq_free(&enic->cq[i]);
|
||||
for (i = 0; i < enic->intr_count; i++)
|
||||
vnic_intr_free(&enic->intr[i]);
|
||||
}
|
||||
|
||||
void enic_get_res_counts(struct enic *enic)
|
||||
{
|
||||
enic->wq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_WQ);
|
||||
enic->rq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_RQ);
|
||||
enic->cq_count = vnic_dev_get_res_count(enic->vdev, RES_TYPE_CQ);
|
||||
enic->intr_count = vnic_dev_get_res_count(enic->vdev,
|
||||
RES_TYPE_INTR_CTRL);
|
||||
|
||||
printk(KERN_INFO PFX "vNIC resources avail: "
|
||||
"wq %d rq %d cq %d intr %d\n",
|
||||
enic->wq_count, enic->rq_count,
|
||||
enic->cq_count, enic->intr_count);
|
||||
}
|
||||
|
||||
void enic_init_vnic_resources(struct enic *enic)
|
||||
{
|
||||
enum vnic_dev_intr_mode intr_mode;
|
||||
unsigned int mask_on_assertion;
|
||||
unsigned int interrupt_offset;
|
||||
unsigned int error_interrupt_enable;
|
||||
unsigned int error_interrupt_offset;
|
||||
unsigned int cq_index;
|
||||
unsigned int i;
|
||||
|
||||
intr_mode = vnic_dev_get_intr_mode(enic->vdev);
|
||||
|
||||
/* Init RQ/WQ resources.
|
||||
*
|
||||
* RQ[0 - n-1] point to CQ[0 - n-1]
|
||||
* WQ[0 - m-1] point to CQ[n - n+m-1]
|
||||
*
|
||||
* Error interrupt is not enabled for MSI.
|
||||
*/
|
||||
|
||||
switch (intr_mode) {
|
||||
case VNIC_DEV_INTR_MODE_INTX:
|
||||
case VNIC_DEV_INTR_MODE_MSIX:
|
||||
error_interrupt_enable = 1;
|
||||
error_interrupt_offset = enic->intr_count - 2;
|
||||
break;
|
||||
default:
|
||||
error_interrupt_enable = 0;
|
||||
error_interrupt_offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < enic->rq_count; i++) {
|
||||
cq_index = i;
|
||||
vnic_rq_init(&enic->rq[i],
|
||||
cq_index,
|
||||
error_interrupt_enable,
|
||||
error_interrupt_offset);
|
||||
}
|
||||
|
||||
for (i = 0; i < enic->wq_count; i++) {
|
||||
cq_index = enic->rq_count + i;
|
||||
vnic_wq_init(&enic->wq[i],
|
||||
cq_index,
|
||||
error_interrupt_enable,
|
||||
error_interrupt_offset);
|
||||
}
|
||||
|
||||
/* Init CQ resources
|
||||
*
|
||||
* CQ[0 - n+m-1] point to INTR[0] for INTx, MSI
|
||||
* CQ[0 - n+m-1] point to INTR[0 - n+m-1] for MSI-X
|
||||
*/
|
||||
|
||||
for (i = 0; i < enic->cq_count; i++) {
|
||||
|
||||
switch (intr_mode) {
|
||||
case VNIC_DEV_INTR_MODE_MSIX:
|
||||
interrupt_offset = i;
|
||||
break;
|
||||
default:
|
||||
interrupt_offset = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
vnic_cq_init(&enic->cq[i],
|
||||
0 /* flow_control_enable */,
|
||||
1 /* color_enable */,
|
||||
0 /* cq_head */,
|
||||
0 /* cq_tail */,
|
||||
1 /* cq_tail_color */,
|
||||
1 /* interrupt_enable */,
|
||||
1 /* cq_entry_enable */,
|
||||
0 /* cq_message_enable */,
|
||||
interrupt_offset,
|
||||
0 /* cq_message_addr */);
|
||||
}
|
||||
|
||||
/* Init INTR resources
|
||||
*
|
||||
* mask_on_assertion is not used for INTx due to the level-
|
||||
* triggered nature of INTx
|
||||
*/
|
||||
|
||||
switch (intr_mode) {
|
||||
case VNIC_DEV_INTR_MODE_MSI:
|
||||
case VNIC_DEV_INTR_MODE_MSIX:
|
||||
mask_on_assertion = 1;
|
||||
break;
|
||||
default:
|
||||
mask_on_assertion = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < enic->intr_count; i++) {
|
||||
vnic_intr_init(&enic->intr[i],
|
||||
enic->config.intr_timer,
|
||||
enic->config.intr_timer_type,
|
||||
mask_on_assertion);
|
||||
}
|
||||
|
||||
/* Clear LIF stats
|
||||
*/
|
||||
|
||||
vnic_dev_stats_clear(enic->vdev);
|
||||
}
|
||||
|
||||
int enic_alloc_vnic_resources(struct enic *enic)
|
||||
{
|
||||
enum vnic_dev_intr_mode intr_mode;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
intr_mode = vnic_dev_get_intr_mode(enic->vdev);
|
||||
|
||||
printk(KERN_INFO PFX "vNIC resources used: "
|
||||
"wq %d rq %d cq %d intr %d intr mode %s\n",
|
||||
enic->wq_count, enic->rq_count,
|
||||
enic->cq_count, enic->intr_count,
|
||||
intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" :
|
||||
intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" :
|
||||
intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" :
|
||||
"unknown"
|
||||
);
|
||||
|
||||
/* Allocate queue resources
|
||||
*/
|
||||
|
||||
for (i = 0; i < enic->wq_count; i++) {
|
||||
err = vnic_wq_alloc(enic->vdev, &enic->wq[i], i,
|
||||
enic->config.wq_desc_count,
|
||||
sizeof(struct wq_enet_desc));
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < enic->rq_count; i++) {
|
||||
err = vnic_rq_alloc(enic->vdev, &enic->rq[i], i,
|
||||
enic->config.rq_desc_count,
|
||||
sizeof(struct rq_enet_desc));
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < enic->cq_count; i++) {
|
||||
if (i < enic->rq_count)
|
||||
err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
|
||||
enic->config.rq_desc_count,
|
||||
sizeof(struct cq_enet_rq_desc));
|
||||
else
|
||||
err = vnic_cq_alloc(enic->vdev, &enic->cq[i], i,
|
||||
enic->config.wq_desc_count,
|
||||
sizeof(struct cq_enet_wq_desc));
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
for (i = 0; i < enic->intr_count; i++) {
|
||||
err = vnic_intr_alloc(enic->vdev, &enic->intr[i], i);
|
||||
if (err)
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
/* Hook remaining resource
|
||||
*/
|
||||
|
||||
enic->legacy_pba = vnic_dev_get_res(enic->vdev,
|
||||
RES_TYPE_INTR_PBA_LEGACY, 0);
|
||||
if (!enic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) {
|
||||
printk(KERN_ERR PFX "Failed to hook legacy pba resource\n");
|
||||
err = -ENODEV;
|
||||
goto err_out_cleanup;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_cleanup:
|
||||
enic_free_vnic_resources(enic);
|
||||
|
||||
return err;
|
||||
}
|
||||
151
drivers/net/enic/enic_res.h
Normal file
151
drivers/net/enic/enic_res.h
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ENIC_RES_H_
|
||||
#define _ENIC_RES_H_
|
||||
|
||||
#include "wq_enet_desc.h"
|
||||
#include "rq_enet_desc.h"
|
||||
#include "vnic_wq.h"
|
||||
#include "vnic_rq.h"
|
||||
|
||||
#define ENIC_MIN_WQ_DESCS 64
|
||||
#define ENIC_MAX_WQ_DESCS 4096
|
||||
#define ENIC_MIN_RQ_DESCS 64
|
||||
#define ENIC_MAX_RQ_DESCS 4096
|
||||
|
||||
#define ENIC_MIN_MTU 576 /* minimum for IPv4 */
|
||||
#define ENIC_MAX_MTU 9000
|
||||
|
||||
#define ENIC_MULTICAST_PERFECT_FILTERS 32
|
||||
|
||||
#define ENIC_NON_TSO_MAX_DESC 16
|
||||
|
||||
#define ENIC_SETTING(enic, f) ((enic->config.flags & VENETF_##f) ? 1 : 0)
|
||||
|
||||
static inline void enic_queue_wq_desc_ex(struct vnic_wq *wq,
|
||||
void *os_buf, dma_addr_t dma_addr, unsigned int len,
|
||||
unsigned int mss_or_csum_offset, unsigned int hdr_len,
|
||||
int vlan_tag_insert, unsigned int vlan_tag,
|
||||
int offload_mode, int cq_entry, int sop, int eop)
|
||||
{
|
||||
struct wq_enet_desc *desc = vnic_wq_next_desc(wq);
|
||||
|
||||
wq_enet_desc_enc(desc,
|
||||
(u64)dma_addr | VNIC_PADDR_TARGET,
|
||||
(u16)len,
|
||||
(u16)mss_or_csum_offset,
|
||||
(u16)hdr_len, (u8)offload_mode,
|
||||
(u8)eop, (u8)cq_entry,
|
||||
0, /* fcoe_encap */
|
||||
(u8)vlan_tag_insert,
|
||||
(u16)vlan_tag,
|
||||
0 /* loopback */);
|
||||
|
||||
wmb();
|
||||
|
||||
vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop);
|
||||
}
|
||||
|
||||
static inline void enic_queue_wq_desc_cont(struct vnic_wq *wq,
|
||||
void *os_buf, dma_addr_t dma_addr, unsigned int len, int eop)
|
||||
{
|
||||
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
|
||||
0, 0, 0, 0, 0,
|
||||
eop, 0 /* !SOP */, eop);
|
||||
}
|
||||
|
||||
static inline void enic_queue_wq_desc(struct vnic_wq *wq, void *os_buf,
|
||||
dma_addr_t dma_addr, unsigned int len, int vlan_tag_insert,
|
||||
unsigned int vlan_tag, int eop)
|
||||
{
|
||||
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
|
||||
0, 0, vlan_tag_insert, vlan_tag,
|
||||
WQ_ENET_OFFLOAD_MODE_CSUM,
|
||||
eop, 1 /* SOP */, eop);
|
||||
}
|
||||
|
||||
static inline void enic_queue_wq_desc_csum(struct vnic_wq *wq,
|
||||
void *os_buf, dma_addr_t dma_addr, unsigned int len,
|
||||
int ip_csum, int tcpudp_csum, int vlan_tag_insert,
|
||||
unsigned int vlan_tag, int eop)
|
||||
{
|
||||
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
|
||||
(ip_csum ? 1 : 0) + (tcpudp_csum ? 2 : 0),
|
||||
0, vlan_tag_insert, vlan_tag,
|
||||
WQ_ENET_OFFLOAD_MODE_CSUM,
|
||||
eop, 1 /* SOP */, eop);
|
||||
}
|
||||
|
||||
static inline void enic_queue_wq_desc_csum_l4(struct vnic_wq *wq,
|
||||
void *os_buf, dma_addr_t dma_addr, unsigned int len,
|
||||
unsigned int csum_offset, unsigned int hdr_len,
|
||||
int vlan_tag_insert, unsigned int vlan_tag, int eop)
|
||||
{
|
||||
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
|
||||
csum_offset, hdr_len, vlan_tag_insert, vlan_tag,
|
||||
WQ_ENET_OFFLOAD_MODE_CSUM_L4,
|
||||
eop, 1 /* SOP */, eop);
|
||||
}
|
||||
|
||||
static inline void enic_queue_wq_desc_tso(struct vnic_wq *wq,
|
||||
void *os_buf, dma_addr_t dma_addr, unsigned int len,
|
||||
unsigned int mss, unsigned int hdr_len, int vlan_tag_insert,
|
||||
unsigned int vlan_tag, int eop)
|
||||
{
|
||||
enic_queue_wq_desc_ex(wq, os_buf, dma_addr, len,
|
||||
mss, hdr_len, vlan_tag_insert, vlan_tag,
|
||||
WQ_ENET_OFFLOAD_MODE_TSO,
|
||||
eop, 1 /* SOP */, eop);
|
||||
}
|
||||
|
||||
static inline void enic_queue_rq_desc(struct vnic_rq *rq,
|
||||
void *os_buf, unsigned int os_buf_index,
|
||||
dma_addr_t dma_addr, unsigned int len)
|
||||
{
|
||||
struct rq_enet_desc *desc = vnic_rq_next_desc(rq);
|
||||
u8 type = os_buf_index ?
|
||||
RQ_ENET_TYPE_NOT_SOP : RQ_ENET_TYPE_ONLY_SOP;
|
||||
|
||||
rq_enet_desc_enc(desc,
|
||||
(u64)dma_addr | VNIC_PADDR_TARGET,
|
||||
type, (u16)len);
|
||||
|
||||
wmb();
|
||||
|
||||
vnic_rq_post(rq, os_buf, os_buf_index, dma_addr, len);
|
||||
}
|
||||
|
||||
struct enic;
|
||||
|
||||
int enic_get_vnic_config(struct enic *);
|
||||
void enic_add_station_addr(struct enic *enic);
|
||||
void enic_add_multicast_addr(struct enic *enic, u8 *addr);
|
||||
void enic_del_multicast_addr(struct enic *enic, u8 *addr);
|
||||
void enic_add_vlan(struct enic *enic, u16 vlanid);
|
||||
void enic_del_vlan(struct enic *enic, u16 vlanid);
|
||||
int enic_set_nic_cfg(struct enic *enic, u8 rss_default_cpu, u8 rss_hash_type,
|
||||
u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, u8 tso_ipid_split_en,
|
||||
u8 ig_vlan_strip_en);
|
||||
void enic_get_res_counts(struct enic *enic);
|
||||
void enic_init_vnic_resources(struct enic *enic);
|
||||
int enic_alloc_vnic_resources(struct enic *);
|
||||
void enic_free_vnic_resources(struct enic *);
|
||||
|
||||
#endif /* _ENIC_RES_H_ */
|
||||
60
drivers/net/enic/rq_enet_desc.h
Normal file
60
drivers/net/enic/rq_enet_desc.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _RQ_ENET_DESC_H_
|
||||
#define _RQ_ENET_DESC_H_
|
||||
|
||||
/* Ethernet receive queue descriptor: 16B */
|
||||
struct rq_enet_desc {
|
||||
__le64 address;
|
||||
__le16 length_type;
|
||||
u8 reserved[6];
|
||||
};
|
||||
|
||||
enum rq_enet_type_types {
|
||||
RQ_ENET_TYPE_ONLY_SOP = 0,
|
||||
RQ_ENET_TYPE_NOT_SOP = 1,
|
||||
RQ_ENET_TYPE_RESV2 = 2,
|
||||
RQ_ENET_TYPE_RESV3 = 3,
|
||||
};
|
||||
|
||||
#define RQ_ENET_ADDR_BITS 64
|
||||
#define RQ_ENET_LEN_BITS 14
|
||||
#define RQ_ENET_LEN_MASK ((1 << RQ_ENET_LEN_BITS) - 1)
|
||||
#define RQ_ENET_TYPE_BITS 2
|
||||
#define RQ_ENET_TYPE_MASK ((1 << RQ_ENET_TYPE_BITS) - 1)
|
||||
|
||||
static inline void rq_enet_desc_enc(struct rq_enet_desc *desc,
|
||||
u64 address, u8 type, u16 length)
|
||||
{
|
||||
desc->address = cpu_to_le64(address);
|
||||
desc->length_type = cpu_to_le16((length & RQ_ENET_LEN_MASK) |
|
||||
((type & RQ_ENET_TYPE_MASK) << RQ_ENET_LEN_BITS));
|
||||
}
|
||||
|
||||
static inline void rq_enet_desc_dec(struct rq_enet_desc *desc,
|
||||
u64 *address, u8 *type, u16 *length)
|
||||
{
|
||||
*address = le64_to_cpu(desc->address);
|
||||
*length = le16_to_cpu(desc->length_type) & RQ_ENET_LEN_MASK;
|
||||
*type = (u8)((le16_to_cpu(desc->length_type) >> RQ_ENET_LEN_BITS) &
|
||||
RQ_ENET_TYPE_MASK);
|
||||
}
|
||||
|
||||
#endif /* _RQ_ENET_DESC_H_ */
|
||||
89
drivers/net/enic/vnic_cq.c
Normal file
89
drivers/net/enic/vnic_cq.c
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_cq.h"
|
||||
|
||||
void vnic_cq_free(struct vnic_cq *cq)
|
||||
{
|
||||
vnic_dev_free_desc_ring(cq->vdev, &cq->ring);
|
||||
|
||||
cq->ctrl = NULL;
|
||||
}
|
||||
|
||||
int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index,
|
||||
unsigned int desc_count, unsigned int desc_size)
|
||||
{
|
||||
int err;
|
||||
|
||||
cq->index = index;
|
||||
cq->vdev = vdev;
|
||||
|
||||
cq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_CQ, index);
|
||||
if (!cq->ctrl) {
|
||||
printk(KERN_ERR "Failed to hook CQ[%d] resource\n", index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = vnic_dev_alloc_desc_ring(vdev, &cq->ring, desc_count, desc_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable,
|
||||
unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail,
|
||||
unsigned int cq_tail_color, unsigned int interrupt_enable,
|
||||
unsigned int cq_entry_enable, unsigned int cq_message_enable,
|
||||
unsigned int interrupt_offset, u64 cq_message_addr)
|
||||
{
|
||||
u64 paddr;
|
||||
|
||||
paddr = (u64)cq->ring.base_addr | VNIC_PADDR_TARGET;
|
||||
writeq(paddr, &cq->ctrl->ring_base);
|
||||
iowrite32(cq->ring.desc_count, &cq->ctrl->ring_size);
|
||||
iowrite32(flow_control_enable, &cq->ctrl->flow_control_enable);
|
||||
iowrite32(color_enable, &cq->ctrl->color_enable);
|
||||
iowrite32(cq_head, &cq->ctrl->cq_head);
|
||||
iowrite32(cq_tail, &cq->ctrl->cq_tail);
|
||||
iowrite32(cq_tail_color, &cq->ctrl->cq_tail_color);
|
||||
iowrite32(interrupt_enable, &cq->ctrl->interrupt_enable);
|
||||
iowrite32(cq_entry_enable, &cq->ctrl->cq_entry_enable);
|
||||
iowrite32(cq_message_enable, &cq->ctrl->cq_message_enable);
|
||||
iowrite32(interrupt_offset, &cq->ctrl->interrupt_offset);
|
||||
writeq(cq_message_addr, &cq->ctrl->cq_message_addr);
|
||||
}
|
||||
|
||||
void vnic_cq_clean(struct vnic_cq *cq)
|
||||
{
|
||||
cq->to_clean = 0;
|
||||
cq->last_color = 0;
|
||||
|
||||
iowrite32(0, &cq->ctrl->cq_head);
|
||||
iowrite32(0, &cq->ctrl->cq_tail);
|
||||
iowrite32(1, &cq->ctrl->cq_tail_color);
|
||||
|
||||
vnic_dev_clear_desc_ring(&cq->ring);
|
||||
}
|
||||
113
drivers/net/enic/vnic_cq.h
Normal file
113
drivers/net/enic/vnic_cq.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_CQ_H_
|
||||
#define _VNIC_CQ_H_
|
||||
|
||||
#include "cq_desc.h"
|
||||
#include "vnic_dev.h"
|
||||
|
||||
/* Completion queue control */
|
||||
struct vnic_cq_ctrl {
|
||||
u64 ring_base; /* 0x00 */
|
||||
u32 ring_size; /* 0x08 */
|
||||
u32 pad0;
|
||||
u32 flow_control_enable; /* 0x10 */
|
||||
u32 pad1;
|
||||
u32 color_enable; /* 0x18 */
|
||||
u32 pad2;
|
||||
u32 cq_head; /* 0x20 */
|
||||
u32 pad3;
|
||||
u32 cq_tail; /* 0x28 */
|
||||
u32 pad4;
|
||||
u32 cq_tail_color; /* 0x30 */
|
||||
u32 pad5;
|
||||
u32 interrupt_enable; /* 0x38 */
|
||||
u32 pad6;
|
||||
u32 cq_entry_enable; /* 0x40 */
|
||||
u32 pad7;
|
||||
u32 cq_message_enable; /* 0x48 */
|
||||
u32 pad8;
|
||||
u32 interrupt_offset; /* 0x50 */
|
||||
u32 pad9;
|
||||
u64 cq_message_addr; /* 0x58 */
|
||||
u32 pad10;
|
||||
};
|
||||
|
||||
struct vnic_cq {
|
||||
unsigned int index;
|
||||
struct vnic_dev *vdev;
|
||||
struct vnic_cq_ctrl __iomem *ctrl; /* memory-mapped */
|
||||
struct vnic_dev_ring ring;
|
||||
unsigned int to_clean;
|
||||
unsigned int last_color;
|
||||
};
|
||||
|
||||
static inline unsigned int vnic_cq_service(struct vnic_cq *cq,
|
||||
unsigned int work_to_do,
|
||||
int (*q_service)(struct vnic_dev *vdev, struct cq_desc *cq_desc,
|
||||
u8 type, u16 q_number, u16 completed_index, void *opaque),
|
||||
void *opaque)
|
||||
{
|
||||
struct cq_desc *cq_desc;
|
||||
unsigned int work_done = 0;
|
||||
u16 q_number, completed_index;
|
||||
u8 type, color;
|
||||
|
||||
cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs +
|
||||
cq->ring.desc_size * cq->to_clean);
|
||||
cq_desc_dec(cq_desc, &type, &color,
|
||||
&q_number, &completed_index);
|
||||
|
||||
while (color != cq->last_color) {
|
||||
|
||||
if ((*q_service)(cq->vdev, cq_desc, type,
|
||||
q_number, completed_index, opaque))
|
||||
break;
|
||||
|
||||
cq->to_clean++;
|
||||
if (cq->to_clean == cq->ring.desc_count) {
|
||||
cq->to_clean = 0;
|
||||
cq->last_color = cq->last_color ? 0 : 1;
|
||||
}
|
||||
|
||||
cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs +
|
||||
cq->ring.desc_size * cq->to_clean);
|
||||
cq_desc_dec(cq_desc, &type, &color,
|
||||
&q_number, &completed_index);
|
||||
|
||||
work_done++;
|
||||
if (work_done >= work_to_do)
|
||||
break;
|
||||
}
|
||||
|
||||
return work_done;
|
||||
}
|
||||
|
||||
void vnic_cq_free(struct vnic_cq *cq);
|
||||
int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index,
|
||||
unsigned int desc_count, unsigned int desc_size);
|
||||
void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable,
|
||||
unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail,
|
||||
unsigned int cq_tail_color, unsigned int interrupt_enable,
|
||||
unsigned int cq_entry_enable, unsigned int message_enable,
|
||||
unsigned int interrupt_offset, u64 message_addr);
|
||||
void vnic_cq_clean(struct vnic_cq *cq);
|
||||
|
||||
#endif /* _VNIC_CQ_H_ */
|
||||
674
drivers/net/enic/vnic_dev.c
Normal file
674
drivers/net/enic/vnic_dev.c
Normal file
|
|
@ -0,0 +1,674 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include "vnic_resource.h"
|
||||
#include "vnic_devcmd.h"
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_stats.h"
|
||||
|
||||
struct vnic_res {
|
||||
void __iomem *vaddr;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
struct vnic_dev {
|
||||
void *priv;
|
||||
struct pci_dev *pdev;
|
||||
struct vnic_res res[RES_TYPE_MAX];
|
||||
enum vnic_dev_intr_mode intr_mode;
|
||||
struct vnic_devcmd __iomem *devcmd;
|
||||
struct vnic_devcmd_notify *notify;
|
||||
struct vnic_devcmd_notify notify_copy;
|
||||
dma_addr_t notify_pa;
|
||||
u32 *linkstatus;
|
||||
dma_addr_t linkstatus_pa;
|
||||
struct vnic_stats *stats;
|
||||
dma_addr_t stats_pa;
|
||||
struct vnic_devcmd_fw_info *fw_info;
|
||||
dma_addr_t fw_info_pa;
|
||||
};
|
||||
|
||||
#define VNIC_MAX_RES_HDR_SIZE \
|
||||
(sizeof(struct vnic_resource_header) + \
|
||||
sizeof(struct vnic_resource) * RES_TYPE_MAX)
|
||||
#define VNIC_RES_STRIDE 128
|
||||
|
||||
void *vnic_dev_priv(struct vnic_dev *vdev)
|
||||
{
|
||||
return vdev->priv;
|
||||
}
|
||||
|
||||
static int vnic_dev_discover_res(struct vnic_dev *vdev,
|
||||
struct vnic_dev_bar *bar)
|
||||
{
|
||||
struct vnic_resource_header __iomem *rh;
|
||||
struct vnic_resource __iomem *r;
|
||||
u8 type;
|
||||
|
||||
if (bar->len < VNIC_MAX_RES_HDR_SIZE) {
|
||||
printk(KERN_ERR "vNIC BAR0 res hdr length error\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rh = bar->vaddr;
|
||||
if (!rh) {
|
||||
printk(KERN_ERR "vNIC BAR0 res hdr not mem-mapped\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ioread32(&rh->magic) != VNIC_RES_MAGIC ||
|
||||
ioread32(&rh->version) != VNIC_RES_VERSION) {
|
||||
printk(KERN_ERR "vNIC BAR0 res magic/version error "
|
||||
"exp (%lx/%lx) curr (%x/%x)\n",
|
||||
VNIC_RES_MAGIC, VNIC_RES_VERSION,
|
||||
ioread32(&rh->magic), ioread32(&rh->version));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = (struct vnic_resource __iomem *)(rh + 1);
|
||||
|
||||
while ((type = ioread8(&r->type)) != RES_TYPE_EOL) {
|
||||
|
||||
u8 bar_num = ioread8(&r->bar);
|
||||
u32 bar_offset = ioread32(&r->bar_offset);
|
||||
u32 count = ioread32(&r->count);
|
||||
u32 len;
|
||||
|
||||
r++;
|
||||
|
||||
if (bar_num != 0) /* only mapping in BAR0 resources */
|
||||
continue;
|
||||
|
||||
switch (type) {
|
||||
case RES_TYPE_WQ:
|
||||
case RES_TYPE_RQ:
|
||||
case RES_TYPE_CQ:
|
||||
case RES_TYPE_INTR_CTRL:
|
||||
/* each count is stride bytes long */
|
||||
len = count * VNIC_RES_STRIDE;
|
||||
if (len + bar_offset > bar->len) {
|
||||
printk(KERN_ERR "vNIC BAR0 resource %d "
|
||||
"out-of-bounds, offset 0x%x + "
|
||||
"size 0x%x > bar len 0x%lx\n",
|
||||
type, bar_offset,
|
||||
len,
|
||||
bar->len);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case RES_TYPE_INTR_PBA_LEGACY:
|
||||
case RES_TYPE_DEVCMD:
|
||||
len = count;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
vdev->res[type].count = count;
|
||||
vdev->res[type].vaddr = (char __iomem *)bar->vaddr + bar_offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev,
|
||||
enum vnic_res_type type)
|
||||
{
|
||||
return vdev->res[type].count;
|
||||
}
|
||||
|
||||
void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
|
||||
unsigned int index)
|
||||
{
|
||||
if (!vdev->res[type].vaddr)
|
||||
return NULL;
|
||||
|
||||
switch (type) {
|
||||
case RES_TYPE_WQ:
|
||||
case RES_TYPE_RQ:
|
||||
case RES_TYPE_CQ:
|
||||
case RES_TYPE_INTR_CTRL:
|
||||
return (char __iomem *)vdev->res[type].vaddr +
|
||||
index * VNIC_RES_STRIDE;
|
||||
default:
|
||||
return (char __iomem *)vdev->res[type].vaddr;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring,
|
||||
unsigned int desc_count, unsigned int desc_size)
|
||||
{
|
||||
/* The base address of the desc rings must be 512 byte aligned.
|
||||
* Descriptor count is aligned to groups of 32 descriptors. A
|
||||
* count of 0 means the maximum 4096 descriptors. Descriptor
|
||||
* size is aligned to 16 bytes.
|
||||
*/
|
||||
|
||||
unsigned int count_align = 32;
|
||||
unsigned int desc_align = 16;
|
||||
|
||||
ring->base_align = 512;
|
||||
|
||||
if (desc_count == 0)
|
||||
desc_count = 4096;
|
||||
|
||||
ring->desc_count = ALIGN(desc_count, count_align);
|
||||
|
||||
ring->desc_size = ALIGN(desc_size, desc_align);
|
||||
|
||||
ring->size = ring->desc_count * ring->desc_size;
|
||||
ring->size_unaligned = ring->size + ring->base_align;
|
||||
|
||||
return ring->size_unaligned;
|
||||
}
|
||||
|
||||
void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring)
|
||||
{
|
||||
memset(ring->descs, 0, ring->size);
|
||||
}
|
||||
|
||||
int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
|
||||
unsigned int desc_count, unsigned int desc_size)
|
||||
{
|
||||
vnic_dev_desc_ring_size(ring, desc_count, desc_size);
|
||||
|
||||
ring->descs_unaligned = pci_alloc_consistent(vdev->pdev,
|
||||
ring->size_unaligned,
|
||||
&ring->base_addr_unaligned);
|
||||
|
||||
if (!ring->descs_unaligned) {
|
||||
printk(KERN_ERR
|
||||
"Failed to allocate ring (size=%d), aborting\n",
|
||||
(int)ring->size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ring->base_addr = ALIGN(ring->base_addr_unaligned,
|
||||
ring->base_align);
|
||||
ring->descs = (u8 *)ring->descs_unaligned +
|
||||
(ring->base_addr - ring->base_addr_unaligned);
|
||||
|
||||
vnic_dev_clear_desc_ring(ring);
|
||||
|
||||
ring->desc_avail = ring->desc_count - 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring)
|
||||
{
|
||||
if (ring->descs) {
|
||||
pci_free_consistent(vdev->pdev,
|
||||
ring->size_unaligned,
|
||||
ring->descs_unaligned,
|
||||
ring->base_addr_unaligned);
|
||||
ring->descs = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
|
||||
u64 *a0, u64 *a1, int wait)
|
||||
{
|
||||
struct vnic_devcmd __iomem *devcmd = vdev->devcmd;
|
||||
int delay;
|
||||
u32 status;
|
||||
int dev_cmd_err[] = {
|
||||
/* convert from fw's version of error.h to host's version */
|
||||
0, /* ERR_SUCCESS */
|
||||
EINVAL, /* ERR_EINVAL */
|
||||
EFAULT, /* ERR_EFAULT */
|
||||
EPERM, /* ERR_EPERM */
|
||||
EBUSY, /* ERR_EBUSY */
|
||||
};
|
||||
int err;
|
||||
|
||||
status = ioread32(&devcmd->status);
|
||||
if (status & STAT_BUSY) {
|
||||
printk(KERN_ERR "Busy devcmd %d\n", _CMD_N(cmd));
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) {
|
||||
writeq(*a0, &devcmd->args[0]);
|
||||
writeq(*a1, &devcmd->args[1]);
|
||||
wmb();
|
||||
}
|
||||
|
||||
iowrite32(cmd, &devcmd->cmd);
|
||||
|
||||
if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT))
|
||||
return 0;
|
||||
|
||||
for (delay = 0; delay < wait; delay++) {
|
||||
|
||||
udelay(100);
|
||||
|
||||
status = ioread32(&devcmd->status);
|
||||
if (!(status & STAT_BUSY)) {
|
||||
|
||||
if (status & STAT_ERROR) {
|
||||
err = dev_cmd_err[(int)readq(&devcmd->args[0])];
|
||||
printk(KERN_ERR "Error %d devcmd %d\n",
|
||||
err, _CMD_N(cmd));
|
||||
return -err;
|
||||
}
|
||||
|
||||
if (_CMD_DIR(cmd) & _CMD_DIR_READ) {
|
||||
rmb();
|
||||
*a0 = readq(&devcmd->args[0]);
|
||||
*a1 = readq(&devcmd->args[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
printk(KERN_ERR "Timedout devcmd %d\n", _CMD_N(cmd));
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
int vnic_dev_fw_info(struct vnic_dev *vdev,
|
||||
struct vnic_devcmd_fw_info **fw_info)
|
||||
{
|
||||
u64 a0, a1 = 0;
|
||||
int wait = 1000;
|
||||
int err = 0;
|
||||
|
||||
if (!vdev->fw_info) {
|
||||
vdev->fw_info = pci_alloc_consistent(vdev->pdev,
|
||||
sizeof(struct vnic_devcmd_fw_info),
|
||||
&vdev->fw_info_pa);
|
||||
if (!vdev->fw_info)
|
||||
return -ENOMEM;
|
||||
|
||||
a0 = vdev->fw_info_pa;
|
||||
|
||||
/* only get fw_info once and cache it */
|
||||
err = vnic_dev_cmd(vdev, CMD_MCPU_FW_INFO, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
*fw_info = vdev->fw_info;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size,
|
||||
void *value)
|
||||
{
|
||||
u64 a0, a1;
|
||||
int wait = 1000;
|
||||
int err;
|
||||
|
||||
a0 = offset;
|
||||
a1 = size;
|
||||
|
||||
err = vnic_dev_cmd(vdev, CMD_DEV_SPEC, &a0, &a1, wait);
|
||||
|
||||
switch (size) {
|
||||
case 1: *(u8 *)value = (u8)a0; break;
|
||||
case 2: *(u16 *)value = (u16)a0; break;
|
||||
case 4: *(u32 *)value = (u32)a0; break;
|
||||
case 8: *(u64 *)value = a0; break;
|
||||
default: BUG(); break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int vnic_dev_stats_clear(struct vnic_dev *vdev)
|
||||
{
|
||||
u64 a0 = 0, a1 = 0;
|
||||
int wait = 1000;
|
||||
return vnic_dev_cmd(vdev, CMD_STATS_CLEAR, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats)
|
||||
{
|
||||
u64 a0, a1;
|
||||
int wait = 1000;
|
||||
|
||||
if (!vdev->stats) {
|
||||
vdev->stats = pci_alloc_consistent(vdev->pdev,
|
||||
sizeof(struct vnic_stats), &vdev->stats_pa);
|
||||
if (!vdev->stats)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*stats = vdev->stats;
|
||||
a0 = vdev->stats_pa;
|
||||
a1 = sizeof(struct vnic_stats);
|
||||
|
||||
return vnic_dev_cmd(vdev, CMD_STATS_DUMP, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
int vnic_dev_close(struct vnic_dev *vdev)
|
||||
{
|
||||
u64 a0 = 0, a1 = 0;
|
||||
int wait = 1000;
|
||||
return vnic_dev_cmd(vdev, CMD_CLOSE, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
int vnic_dev_enable(struct vnic_dev *vdev)
|
||||
{
|
||||
u64 a0 = 0, a1 = 0;
|
||||
int wait = 1000;
|
||||
return vnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
int vnic_dev_disable(struct vnic_dev *vdev)
|
||||
{
|
||||
u64 a0 = 0, a1 = 0;
|
||||
int wait = 1000;
|
||||
return vnic_dev_cmd(vdev, CMD_DISABLE, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
int vnic_dev_open(struct vnic_dev *vdev, int arg)
|
||||
{
|
||||
u64 a0 = (u32)arg, a1 = 0;
|
||||
int wait = 1000;
|
||||
return vnic_dev_cmd(vdev, CMD_OPEN, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
int vnic_dev_open_done(struct vnic_dev *vdev, int *done)
|
||||
{
|
||||
u64 a0 = 0, a1 = 0;
|
||||
int wait = 1000;
|
||||
int err;
|
||||
|
||||
*done = 0;
|
||||
|
||||
err = vnic_dev_cmd(vdev, CMD_OPEN_STATUS, &a0, &a1, wait);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*done = (a0 == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg)
|
||||
{
|
||||
u64 a0 = (u32)arg, a1 = 0;
|
||||
int wait = 1000;
|
||||
return vnic_dev_cmd(vdev, CMD_SOFT_RESET, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done)
|
||||
{
|
||||
u64 a0 = 0, a1 = 0;
|
||||
int wait = 1000;
|
||||
int err;
|
||||
|
||||
*done = 0;
|
||||
|
||||
err = vnic_dev_cmd(vdev, CMD_SOFT_RESET_STATUS, &a0, &a1, wait);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*done = (a0 == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vnic_dev_hang_notify(struct vnic_dev *vdev)
|
||||
{
|
||||
u64 a0, a1;
|
||||
int wait = 1000;
|
||||
return vnic_dev_cmd(vdev, CMD_HANG_NOTIFY, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr)
|
||||
{
|
||||
u64 a0, a1;
|
||||
int wait = 1000;
|
||||
int err, i;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
mac_addr[i] = 0;
|
||||
|
||||
err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
mac_addr[i] = ((u8 *)&a0)[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
|
||||
int broadcast, int promisc, int allmulti)
|
||||
{
|
||||
u64 a0, a1 = 0;
|
||||
int wait = 1000;
|
||||
int err;
|
||||
|
||||
a0 = (directed ? CMD_PFILTER_DIRECTED : 0) |
|
||||
(multicast ? CMD_PFILTER_MULTICAST : 0) |
|
||||
(broadcast ? CMD_PFILTER_BROADCAST : 0) |
|
||||
(promisc ? CMD_PFILTER_PROMISCUOUS : 0) |
|
||||
(allmulti ? CMD_PFILTER_ALL_MULTICAST : 0);
|
||||
|
||||
err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait);
|
||||
if (err)
|
||||
printk(KERN_ERR "Can't set packet filter\n");
|
||||
}
|
||||
|
||||
void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr)
|
||||
{
|
||||
u64 a0 = 0, a1 = 0;
|
||||
int wait = 1000;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
((u8 *)&a0)[i] = addr[i];
|
||||
|
||||
err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
|
||||
if (err)
|
||||
printk(KERN_ERR
|
||||
"Can't add addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n",
|
||||
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
|
||||
err);
|
||||
}
|
||||
|
||||
void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr)
|
||||
{
|
||||
u64 a0 = 0, a1 = 0;
|
||||
int wait = 1000;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ETH_ALEN; i++)
|
||||
((u8 *)&a0)[i] = addr[i];
|
||||
|
||||
err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait);
|
||||
if (err)
|
||||
printk(KERN_ERR
|
||||
"Can't del addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n",
|
||||
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5],
|
||||
err);
|
||||
}
|
||||
|
||||
int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
|
||||
{
|
||||
u64 a0, a1;
|
||||
int wait = 1000;
|
||||
|
||||
if (!vdev->notify) {
|
||||
vdev->notify = pci_alloc_consistent(vdev->pdev,
|
||||
sizeof(struct vnic_devcmd_notify),
|
||||
&vdev->notify_pa);
|
||||
if (!vdev->notify)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
a0 = vdev->notify_pa;
|
||||
a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL;
|
||||
a1 += sizeof(struct vnic_devcmd_notify);
|
||||
|
||||
return vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
void vnic_dev_notify_unset(struct vnic_dev *vdev)
|
||||
{
|
||||
u64 a0, a1;
|
||||
int wait = 1000;
|
||||
|
||||
a0 = 0; /* paddr = 0 to unset notify buffer */
|
||||
a1 = 0x0000ffff00000000ULL; /* intr num = -1 to unreg for intr */
|
||||
a1 += sizeof(struct vnic_devcmd_notify);
|
||||
|
||||
vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
static int vnic_dev_notify_ready(struct vnic_dev *vdev)
|
||||
{
|
||||
u32 *words;
|
||||
unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4;
|
||||
unsigned int i;
|
||||
u32 csum;
|
||||
|
||||
if (!vdev->notify)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
csum = 0;
|
||||
memcpy(&vdev->notify_copy, vdev->notify,
|
||||
sizeof(struct vnic_devcmd_notify));
|
||||
words = (u32 *)&vdev->notify_copy;
|
||||
for (i = 1; i < nwords; i++)
|
||||
csum += words[i];
|
||||
} while (csum != words[0]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vnic_dev_init(struct vnic_dev *vdev, int arg)
|
||||
{
|
||||
u64 a0 = (u32)arg, a1 = 0;
|
||||
int wait = 1000;
|
||||
return vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait);
|
||||
}
|
||||
|
||||
int vnic_dev_link_status(struct vnic_dev *vdev)
|
||||
{
|
||||
if (vdev->linkstatus)
|
||||
return *vdev->linkstatus;
|
||||
|
||||
if (!vnic_dev_notify_ready(vdev))
|
||||
return 0;
|
||||
|
||||
return vdev->notify_copy.link_state;
|
||||
}
|
||||
|
||||
u32 vnic_dev_port_speed(struct vnic_dev *vdev)
|
||||
{
|
||||
if (!vnic_dev_notify_ready(vdev))
|
||||
return 0;
|
||||
|
||||
return vdev->notify_copy.port_speed;
|
||||
}
|
||||
|
||||
u32 vnic_dev_msg_lvl(struct vnic_dev *vdev)
|
||||
{
|
||||
if (!vnic_dev_notify_ready(vdev))
|
||||
return 0;
|
||||
|
||||
return vdev->notify_copy.msglvl;
|
||||
}
|
||||
|
||||
u32 vnic_dev_mtu(struct vnic_dev *vdev)
|
||||
{
|
||||
if (!vnic_dev_notify_ready(vdev))
|
||||
return 0;
|
||||
|
||||
return vdev->notify_copy.mtu;
|
||||
}
|
||||
|
||||
void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
|
||||
enum vnic_dev_intr_mode intr_mode)
|
||||
{
|
||||
vdev->intr_mode = intr_mode;
|
||||
}
|
||||
|
||||
enum vnic_dev_intr_mode vnic_dev_get_intr_mode(
|
||||
struct vnic_dev *vdev)
|
||||
{
|
||||
return vdev->intr_mode;
|
||||
}
|
||||
|
||||
void vnic_dev_unregister(struct vnic_dev *vdev)
|
||||
{
|
||||
if (vdev) {
|
||||
if (vdev->notify)
|
||||
pci_free_consistent(vdev->pdev,
|
||||
sizeof(struct vnic_devcmd_notify),
|
||||
vdev->notify,
|
||||
vdev->notify_pa);
|
||||
if (vdev->linkstatus)
|
||||
pci_free_consistent(vdev->pdev,
|
||||
sizeof(u32),
|
||||
vdev->linkstatus,
|
||||
vdev->linkstatus_pa);
|
||||
if (vdev->stats)
|
||||
pci_free_consistent(vdev->pdev,
|
||||
sizeof(struct vnic_dev),
|
||||
vdev->stats, vdev->stats_pa);
|
||||
if (vdev->fw_info)
|
||||
pci_free_consistent(vdev->pdev,
|
||||
sizeof(struct vnic_devcmd_fw_info),
|
||||
vdev->fw_info, vdev->fw_info_pa);
|
||||
kfree(vdev);
|
||||
}
|
||||
}
|
||||
|
||||
struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
|
||||
void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar)
|
||||
{
|
||||
if (!vdev) {
|
||||
vdev = kzalloc(sizeof(struct vnic_dev), GFP_ATOMIC);
|
||||
if (!vdev)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
vdev->priv = priv;
|
||||
vdev->pdev = pdev;
|
||||
|
||||
if (vnic_dev_discover_res(vdev, bar))
|
||||
goto err_out;
|
||||
|
||||
vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0);
|
||||
if (!vdev->devcmd)
|
||||
goto err_out;
|
||||
|
||||
return vdev;
|
||||
|
||||
err_out:
|
||||
vnic_dev_unregister(vdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
120
drivers/net/enic/vnic_dev.h
Normal file
120
drivers/net/enic/vnic_dev.h
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_DEV_H_
|
||||
#define _VNIC_DEV_H_
|
||||
|
||||
#include "vnic_resource.h"
|
||||
#include "vnic_devcmd.h"
|
||||
|
||||
#ifndef VNIC_PADDR_TARGET
|
||||
#define VNIC_PADDR_TARGET 0x0000000000000000ULL
|
||||
#endif
|
||||
|
||||
#ifndef readq
|
||||
static inline u64 readq(void __iomem *reg)
|
||||
{
|
||||
return (((u64)readl(reg + 0x4UL) << 32) |
|
||||
(u64)readl(reg));
|
||||
}
|
||||
|
||||
static inline void writeq(u64 val, void __iomem *reg)
|
||||
{
|
||||
writel(val & 0xffffffff, reg);
|
||||
writel(val >> 32, reg + 0x4UL);
|
||||
}
|
||||
#endif
|
||||
|
||||
enum vnic_dev_intr_mode {
|
||||
VNIC_DEV_INTR_MODE_UNKNOWN,
|
||||
VNIC_DEV_INTR_MODE_INTX,
|
||||
VNIC_DEV_INTR_MODE_MSI,
|
||||
VNIC_DEV_INTR_MODE_MSIX,
|
||||
};
|
||||
|
||||
struct vnic_dev_bar {
|
||||
void __iomem *vaddr;
|
||||
dma_addr_t bus_addr;
|
||||
unsigned long len;
|
||||
};
|
||||
|
||||
struct vnic_dev_ring {
|
||||
void *descs;
|
||||
size_t size;
|
||||
dma_addr_t base_addr;
|
||||
size_t base_align;
|
||||
void *descs_unaligned;
|
||||
size_t size_unaligned;
|
||||
dma_addr_t base_addr_unaligned;
|
||||
unsigned int desc_size;
|
||||
unsigned int desc_count;
|
||||
unsigned int desc_avail;
|
||||
};
|
||||
|
||||
struct vnic_dev;
|
||||
struct vnic_stats;
|
||||
|
||||
void *vnic_dev_priv(struct vnic_dev *vdev);
|
||||
unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev,
|
||||
enum vnic_res_type type);
|
||||
void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type,
|
||||
unsigned int index);
|
||||
unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring,
|
||||
unsigned int desc_count, unsigned int desc_size);
|
||||
void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring);
|
||||
int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
|
||||
unsigned int desc_count, unsigned int desc_size);
|
||||
void vnic_dev_free_desc_ring(struct vnic_dev *vdev,
|
||||
struct vnic_dev_ring *ring);
|
||||
int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
|
||||
u64 *a0, u64 *a1, int wait);
|
||||
int vnic_dev_fw_info(struct vnic_dev *vdev,
|
||||
struct vnic_devcmd_fw_info **fw_info);
|
||||
int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size,
|
||||
void *value);
|
||||
int vnic_dev_stats_clear(struct vnic_dev *vdev);
|
||||
int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats);
|
||||
int vnic_dev_hang_notify(struct vnic_dev *vdev);
|
||||
void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
|
||||
int broadcast, int promisc, int allmulti);
|
||||
void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr);
|
||||
void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr);
|
||||
int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
|
||||
int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr);
|
||||
void vnic_dev_notify_unset(struct vnic_dev *vdev);
|
||||
int vnic_dev_link_status(struct vnic_dev *vdev);
|
||||
u32 vnic_dev_port_speed(struct vnic_dev *vdev);
|
||||
u32 vnic_dev_msg_lvl(struct vnic_dev *vdev);
|
||||
u32 vnic_dev_mtu(struct vnic_dev *vdev);
|
||||
int vnic_dev_close(struct vnic_dev *vdev);
|
||||
int vnic_dev_enable(struct vnic_dev *vdev);
|
||||
int vnic_dev_disable(struct vnic_dev *vdev);
|
||||
int vnic_dev_open(struct vnic_dev *vdev, int arg);
|
||||
int vnic_dev_open_done(struct vnic_dev *vdev, int *done);
|
||||
int vnic_dev_init(struct vnic_dev *vdev, int arg);
|
||||
int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg);
|
||||
int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done);
|
||||
void vnic_dev_set_intr_mode(struct vnic_dev *vdev,
|
||||
enum vnic_dev_intr_mode intr_mode);
|
||||
enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev);
|
||||
void vnic_dev_unregister(struct vnic_dev *vdev);
|
||||
struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
|
||||
void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar);
|
||||
|
||||
#endif /* _VNIC_DEV_H_ */
|
||||
282
drivers/net/enic/vnic_devcmd.h
Normal file
282
drivers/net/enic/vnic_devcmd.h
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_DEVCMD_H_
|
||||
#define _VNIC_DEVCMD_H_
|
||||
|
||||
#define _CMD_NBITS 14
|
||||
#define _CMD_VTYPEBITS 10
|
||||
#define _CMD_FLAGSBITS 6
|
||||
#define _CMD_DIRBITS 2
|
||||
|
||||
#define _CMD_NMASK ((1 << _CMD_NBITS)-1)
|
||||
#define _CMD_VTYPEMASK ((1 << _CMD_VTYPEBITS)-1)
|
||||
#define _CMD_FLAGSMASK ((1 << _CMD_FLAGSBITS)-1)
|
||||
#define _CMD_DIRMASK ((1 << _CMD_DIRBITS)-1)
|
||||
|
||||
#define _CMD_NSHIFT 0
|
||||
#define _CMD_VTYPESHIFT (_CMD_NSHIFT+_CMD_NBITS)
|
||||
#define _CMD_FLAGSSHIFT (_CMD_VTYPESHIFT+_CMD_VTYPEBITS)
|
||||
#define _CMD_DIRSHIFT (_CMD_FLAGSSHIFT+_CMD_FLAGSBITS)
|
||||
|
||||
/*
|
||||
* Direction bits (from host perspective).
|
||||
*/
|
||||
#define _CMD_DIR_NONE 0U
|
||||
#define _CMD_DIR_WRITE 1U
|
||||
#define _CMD_DIR_READ 2U
|
||||
#define _CMD_DIR_RW (_CMD_DIR_WRITE | _CMD_DIR_READ)
|
||||
|
||||
/*
|
||||
* Flag bits.
|
||||
*/
|
||||
#define _CMD_FLAGS_NONE 0U
|
||||
#define _CMD_FLAGS_NOWAIT 1U
|
||||
|
||||
/*
|
||||
* vNIC type bits.
|
||||
*/
|
||||
#define _CMD_VTYPE_NONE 0U
|
||||
#define _CMD_VTYPE_ENET 1U
|
||||
#define _CMD_VTYPE_FC 2U
|
||||
#define _CMD_VTYPE_SCSI 4U
|
||||
#define _CMD_VTYPE_ALL (_CMD_VTYPE_ENET | _CMD_VTYPE_FC | _CMD_VTYPE_SCSI)
|
||||
|
||||
/*
|
||||
* Used to create cmds..
|
||||
*/
|
||||
#define _CMDCF(dir, flags, vtype, nr) \
|
||||
(((dir) << _CMD_DIRSHIFT) | \
|
||||
((flags) << _CMD_FLAGSSHIFT) | \
|
||||
((vtype) << _CMD_VTYPESHIFT) | \
|
||||
((nr) << _CMD_NSHIFT))
|
||||
#define _CMDC(dir, vtype, nr) _CMDCF(dir, 0, vtype, nr)
|
||||
#define _CMDCNW(dir, vtype, nr) _CMDCF(dir, _CMD_FLAGS_NOWAIT, vtype, nr)
|
||||
|
||||
/*
|
||||
* Used to decode cmds..
|
||||
*/
|
||||
#define _CMD_DIR(cmd) (((cmd) >> _CMD_DIRSHIFT) & _CMD_DIRMASK)
|
||||
#define _CMD_FLAGS(cmd) (((cmd) >> _CMD_FLAGSSHIFT) & _CMD_FLAGSMASK)
|
||||
#define _CMD_VTYPE(cmd) (((cmd) >> _CMD_VTYPESHIFT) & _CMD_VTYPEMASK)
|
||||
#define _CMD_N(cmd) (((cmd) >> _CMD_NSHIFT) & _CMD_NMASK)
|
||||
|
||||
enum vnic_devcmd_cmd {
|
||||
CMD_NONE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_NONE, 0),
|
||||
|
||||
/* mcpu fw info in mem: (u64)a0=paddr to struct vnic_devcmd_fw_info */
|
||||
CMD_MCPU_FW_INFO = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 1),
|
||||
|
||||
/* dev-specific block member:
|
||||
* in: (u16)a0=offset,(u8)a1=size
|
||||
* out: a0=value */
|
||||
CMD_DEV_SPEC = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 2),
|
||||
|
||||
/* stats clear */
|
||||
CMD_STATS_CLEAR = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 3),
|
||||
|
||||
/* stats dump in mem: (u64)a0=paddr to stats area,
|
||||
* (u16)a1=sizeof stats area */
|
||||
CMD_STATS_DUMP = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 4),
|
||||
|
||||
/* set Rx packet filter: (u32)a0=filters (see CMD_PFILTER_*) */
|
||||
CMD_PACKET_FILTER = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 7),
|
||||
|
||||
/* hang detection notification */
|
||||
CMD_HANG_NOTIFY = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 8),
|
||||
|
||||
/* MAC address in (u48)a0 */
|
||||
CMD_MAC_ADDR = _CMDC(_CMD_DIR_READ,
|
||||
_CMD_VTYPE_ENET | _CMD_VTYPE_FC, 9),
|
||||
|
||||
/* disable/enable promisc mode: (u8)a0=0/1 */
|
||||
/***** XXX DEPRECATED *****/
|
||||
CMD_PROMISC_MODE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 10),
|
||||
|
||||
/* disable/enable all-multi mode: (u8)a0=0/1 */
|
||||
/***** XXX DEPRECATED *****/
|
||||
CMD_ALLMULTI_MODE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 11),
|
||||
|
||||
/* add addr from (u48)a0 */
|
||||
CMD_ADDR_ADD = _CMDCNW(_CMD_DIR_WRITE,
|
||||
_CMD_VTYPE_ENET | _CMD_VTYPE_FC, 12),
|
||||
|
||||
/* del addr from (u48)a0 */
|
||||
CMD_ADDR_DEL = _CMDCNW(_CMD_DIR_WRITE,
|
||||
_CMD_VTYPE_ENET | _CMD_VTYPE_FC, 13),
|
||||
|
||||
/* add VLAN id in (u16)a0 */
|
||||
CMD_VLAN_ADD = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 14),
|
||||
|
||||
/* del VLAN id in (u16)a0 */
|
||||
CMD_VLAN_DEL = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 15),
|
||||
|
||||
/* nic_cfg in (u32)a0 */
|
||||
CMD_NIC_CFG = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 16),
|
||||
|
||||
/* union vnic_rss_key in mem: (u64)a0=paddr, (u16)a1=len */
|
||||
CMD_RSS_KEY = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 17),
|
||||
|
||||
/* union vnic_rss_cpu in mem: (u64)a0=paddr, (u16)a1=len */
|
||||
CMD_RSS_CPU = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 18),
|
||||
|
||||
/* initiate softreset */
|
||||
CMD_SOFT_RESET = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 19),
|
||||
|
||||
/* softreset status:
|
||||
* out: a0=0 reset complete, a0=1 reset in progress */
|
||||
CMD_SOFT_RESET_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 20),
|
||||
|
||||
/* set struct vnic_devcmd_notify buffer in mem:
|
||||
* in:
|
||||
* (u64)a0=paddr to notify (set paddr=0 to unset)
|
||||
* (u32)a1 & 0x00000000ffffffff=sizeof(struct vnic_devcmd_notify)
|
||||
* (u16)a1 & 0x0000ffff00000000=intr num (-1 for no intr)
|
||||
* out:
|
||||
* (u32)a1 = effective size
|
||||
*/
|
||||
CMD_NOTIFY = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 21),
|
||||
|
||||
/* UNDI API: (u64)a0=paddr to s_PXENV_UNDI_ struct,
|
||||
* (u8)a1=PXENV_UNDI_xxx */
|
||||
CMD_UNDI = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 22),
|
||||
|
||||
/* initiate open sequence (u32)a0=flags (see CMD_OPENF_*) */
|
||||
CMD_OPEN = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 23),
|
||||
|
||||
/* open status:
|
||||
* out: a0=0 open complete, a0=1 open in progress */
|
||||
CMD_OPEN_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 24),
|
||||
|
||||
/* close vnic */
|
||||
CMD_CLOSE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 25),
|
||||
|
||||
/* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */
|
||||
CMD_INIT = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26),
|
||||
|
||||
/* variant of CMD_INIT, with provisioning info
|
||||
* (u64)a0=paddr of vnic_devcmd_provinfo
|
||||
* (u32)a1=sizeof provision info */
|
||||
CMD_INIT_PROV_INFO = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 27),
|
||||
|
||||
/* enable virtual link */
|
||||
CMD_ENABLE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 28),
|
||||
|
||||
/* disable virtual link */
|
||||
CMD_DISABLE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 29),
|
||||
|
||||
/* stats dump all vnics on uplink in mem: (u64)a0=paddr (u32)a1=uif */
|
||||
CMD_STATS_DUMP_ALL = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 30),
|
||||
|
||||
/* init status:
|
||||
* out: a0=0 init complete, a0=1 init in progress
|
||||
* if a0=0, a1=errno */
|
||||
CMD_INIT_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 31),
|
||||
|
||||
/* INT13 API: (u64)a0=paddr to vnic_int13_params struct
|
||||
* (u8)a1=INT13_CMD_xxx */
|
||||
CMD_INT13 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_FC, 32),
|
||||
|
||||
/* logical uplink enable/disable: (u64)a0: 0/1=disable/enable */
|
||||
CMD_LOGICAL_UPLINK = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 33),
|
||||
|
||||
/* undo initialize of virtual link */
|
||||
CMD_DEINIT = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 34),
|
||||
};
|
||||
|
||||
/* flags for CMD_OPEN */
|
||||
#define CMD_OPENF_OPROM 0x1 /* open coming from option rom */
|
||||
|
||||
/* flags for CMD_INIT */
|
||||
#define CMD_INITF_DEFAULT_MAC 0x1 /* init with default mac addr */
|
||||
|
||||
/* flags for CMD_PACKET_FILTER */
|
||||
#define CMD_PFILTER_DIRECTED 0x01
|
||||
#define CMD_PFILTER_MULTICAST 0x02
|
||||
#define CMD_PFILTER_BROADCAST 0x04
|
||||
#define CMD_PFILTER_PROMISCUOUS 0x08
|
||||
#define CMD_PFILTER_ALL_MULTICAST 0x10
|
||||
|
||||
enum vnic_devcmd_status {
|
||||
STAT_NONE = 0,
|
||||
STAT_BUSY = 1 << 0, /* cmd in progress */
|
||||
STAT_ERROR = 1 << 1, /* last cmd caused error (code in a0) */
|
||||
};
|
||||
|
||||
enum vnic_devcmd_error {
|
||||
ERR_SUCCESS = 0,
|
||||
ERR_EINVAL = 1,
|
||||
ERR_EFAULT = 2,
|
||||
ERR_EPERM = 3,
|
||||
ERR_EBUSY = 4,
|
||||
ERR_ECMDUNKNOWN = 5,
|
||||
ERR_EBADSTATE = 6,
|
||||
ERR_ENOMEM = 7,
|
||||
ERR_ETIMEDOUT = 8,
|
||||
ERR_ELINKDOWN = 9,
|
||||
};
|
||||
|
||||
struct vnic_devcmd_fw_info {
|
||||
char fw_version[32];
|
||||
char fw_build[32];
|
||||
char hw_version[32];
|
||||
char hw_serial_number[32];
|
||||
};
|
||||
|
||||
struct vnic_devcmd_notify {
|
||||
u32 csum; /* checksum over following words */
|
||||
|
||||
u32 link_state; /* link up == 1 */
|
||||
u32 port_speed; /* effective port speed (rate limit) */
|
||||
u32 mtu; /* MTU */
|
||||
u32 msglvl; /* requested driver msg lvl */
|
||||
u32 uif; /* uplink interface */
|
||||
u32 status; /* status bits (see VNIC_STF_*) */
|
||||
u32 error; /* error code (see ERR_*) for first ERR */
|
||||
};
|
||||
#define VNIC_STF_FATAL_ERR 0x0001 /* fatal fw error */
|
||||
|
||||
struct vnic_devcmd_provinfo {
|
||||
u8 oui[3];
|
||||
u8 type;
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
/*
|
||||
* Writing cmd register causes STAT_BUSY to get set in status register.
|
||||
* When cmd completes, STAT_BUSY will be cleared.
|
||||
*
|
||||
* If cmd completed successfully STAT_ERROR will be clear
|
||||
* and args registers contain cmd-specific results.
|
||||
*
|
||||
* If cmd error, STAT_ERROR will be set and args[0] contains error code.
|
||||
*
|
||||
* status register is read-only. While STAT_BUSY is set,
|
||||
* all other register contents are read-only.
|
||||
*/
|
||||
|
||||
/* Make sizeof(vnic_devcmd) a power-of-2 for I/O BAR. */
|
||||
#define VNIC_DEVCMD_NARGS 15
|
||||
struct vnic_devcmd {
|
||||
u32 status; /* RO */
|
||||
u32 cmd; /* RW */
|
||||
u64 args[VNIC_DEVCMD_NARGS]; /* RW cmd args (little-endian) */
|
||||
};
|
||||
|
||||
#endif /* _VNIC_DEVCMD_H_ */
|
||||
47
drivers/net/enic/vnic_enet.h
Normal file
47
drivers/net/enic/vnic_enet.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_ENIC_H_
|
||||
#define _VNIC_ENIC_H_
|
||||
|
||||
/* Device-specific region: enet configuration */
|
||||
struct vnic_enet_config {
|
||||
u32 flags;
|
||||
u32 wq_desc_count;
|
||||
u32 rq_desc_count;
|
||||
u16 mtu;
|
||||
u16 intr_timer;
|
||||
u8 intr_timer_type;
|
||||
u8 intr_mode;
|
||||
char devname[16];
|
||||
};
|
||||
|
||||
#define VENETF_TSO 0x1 /* TSO enabled */
|
||||
#define VENETF_LRO 0x2 /* LRO enabled */
|
||||
#define VENETF_RXCSUM 0x4 /* RX csum enabled */
|
||||
#define VENETF_TXCSUM 0x8 /* TX csum enabled */
|
||||
#define VENETF_RSS 0x10 /* RSS enabled */
|
||||
#define VENETF_RSSHASH_IPV4 0x20 /* Hash on IPv4 fields */
|
||||
#define VENETF_RSSHASH_TCPIPV4 0x40 /* Hash on TCP + IPv4 fields */
|
||||
#define VENETF_RSSHASH_IPV6 0x80 /* Hash on IPv6 fields */
|
||||
#define VENETF_RSSHASH_TCPIPV6 0x100 /* Hash on TCP + IPv6 fields */
|
||||
#define VENETF_RSSHASH_IPV6_EX 0x200 /* Hash on IPv6 extended fields */
|
||||
#define VENETF_RSSHASH_TCPIPV6_EX 0x400 /* Hash on TCP + IPv6 ext. fields */
|
||||
|
||||
#endif /* _VNIC_ENIC_H_ */
|
||||
62
drivers/net/enic/vnic_intr.c
Normal file
62
drivers/net/enic/vnic_intr.c
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_intr.h"
|
||||
|
||||
void vnic_intr_free(struct vnic_intr *intr)
|
||||
{
|
||||
intr->ctrl = NULL;
|
||||
}
|
||||
|
||||
int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
|
||||
unsigned int index)
|
||||
{
|
||||
intr->index = index;
|
||||
intr->vdev = vdev;
|
||||
|
||||
intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index);
|
||||
if (!intr->ctrl) {
|
||||
printk(KERN_ERR "Failed to hook INTR[%d].ctrl resource\n",
|
||||
index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
|
||||
unsigned int coalescing_type, unsigned int mask_on_assertion)
|
||||
{
|
||||
iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
|
||||
iowrite32(coalescing_type, &intr->ctrl->coalescing_type);
|
||||
iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion);
|
||||
iowrite32(0, &intr->ctrl->int_credits);
|
||||
}
|
||||
|
||||
void vnic_intr_clean(struct vnic_intr *intr)
|
||||
{
|
||||
iowrite32(0, &intr->ctrl->int_credits);
|
||||
}
|
||||
92
drivers/net/enic/vnic_intr.h
Normal file
92
drivers/net/enic/vnic_intr.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_INTR_H_
|
||||
#define _VNIC_INTR_H_
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
|
||||
#define VNIC_INTR_TIMER_MAX 0xffff
|
||||
|
||||
#define VNIC_INTR_TIMER_TYPE_ABS 0
|
||||
#define VNIC_INTR_TIMER_TYPE_QUIET 1
|
||||
|
||||
/* Interrupt control */
|
||||
struct vnic_intr_ctrl {
|
||||
u32 coalescing_timer; /* 0x00 */
|
||||
u32 pad0;
|
||||
u32 coalescing_value; /* 0x08 */
|
||||
u32 pad1;
|
||||
u32 coalescing_type; /* 0x10 */
|
||||
u32 pad2;
|
||||
u32 mask_on_assertion; /* 0x18 */
|
||||
u32 pad3;
|
||||
u32 mask; /* 0x20 */
|
||||
u32 pad4;
|
||||
u32 int_credits; /* 0x28 */
|
||||
u32 pad5;
|
||||
u32 int_credit_return; /* 0x30 */
|
||||
u32 pad6;
|
||||
};
|
||||
|
||||
struct vnic_intr {
|
||||
unsigned int index;
|
||||
struct vnic_dev *vdev;
|
||||
struct vnic_intr_ctrl __iomem *ctrl; /* memory-mapped */
|
||||
};
|
||||
|
||||
static inline void vnic_intr_unmask(struct vnic_intr *intr)
|
||||
{
|
||||
iowrite32(0, &intr->ctrl->mask);
|
||||
}
|
||||
|
||||
static inline void vnic_intr_mask(struct vnic_intr *intr)
|
||||
{
|
||||
iowrite32(1, &intr->ctrl->mask);
|
||||
}
|
||||
|
||||
static inline void vnic_intr_return_credits(struct vnic_intr *intr,
|
||||
unsigned int credits, int unmask, int reset_timer)
|
||||
{
|
||||
#define VNIC_INTR_UNMASK_SHIFT 16
|
||||
#define VNIC_INTR_RESET_TIMER_SHIFT 17
|
||||
|
||||
u32 int_credit_return = (credits & 0xffff) |
|
||||
(unmask ? (1 << VNIC_INTR_UNMASK_SHIFT) : 0) |
|
||||
(reset_timer ? (1 << VNIC_INTR_RESET_TIMER_SHIFT) : 0);
|
||||
|
||||
iowrite32(int_credit_return, &intr->ctrl->int_credit_return);
|
||||
}
|
||||
|
||||
static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba)
|
||||
{
|
||||
/* get and ack interrupt in one read (clear-and-ack-on-read) */
|
||||
return ioread32(legacy_pba);
|
||||
}
|
||||
|
||||
void vnic_intr_free(struct vnic_intr *intr);
|
||||
int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
|
||||
unsigned int index);
|
||||
void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
|
||||
unsigned int coalescing_type, unsigned int mask_on_assertion);
|
||||
void vnic_intr_clean(struct vnic_intr *intr);
|
||||
|
||||
#endif /* _VNIC_INTR_H_ */
|
||||
65
drivers/net/enic/vnic_nic.h
Normal file
65
drivers/net/enic/vnic_nic.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_NIC_H_
|
||||
#define _VNIC_NIC_H_
|
||||
|
||||
#define NIC_CFG_RSS_DEFAULT_CPU_MASK_FIELD 0xffUL
|
||||
#define NIC_CFG_RSS_DEFAULT_CPU_SHIFT 0
|
||||
#define NIC_CFG_RSS_HASH_TYPE (0xffUL << 8)
|
||||
#define NIC_CFG_RSS_HASH_TYPE_MASK_FIELD 0xffUL
|
||||
#define NIC_CFG_RSS_HASH_TYPE_SHIFT 8
|
||||
#define NIC_CFG_RSS_HASH_BITS (7UL << 16)
|
||||
#define NIC_CFG_RSS_HASH_BITS_MASK_FIELD 7UL
|
||||
#define NIC_CFG_RSS_HASH_BITS_SHIFT 16
|
||||
#define NIC_CFG_RSS_BASE_CPU (7UL << 19)
|
||||
#define NIC_CFG_RSS_BASE_CPU_MASK_FIELD 7UL
|
||||
#define NIC_CFG_RSS_BASE_CPU_SHIFT 19
|
||||
#define NIC_CFG_RSS_ENABLE (1UL << 22)
|
||||
#define NIC_CFG_RSS_ENABLE_MASK_FIELD 1UL
|
||||
#define NIC_CFG_RSS_ENABLE_SHIFT 22
|
||||
#define NIC_CFG_TSO_IPID_SPLIT_EN (1UL << 23)
|
||||
#define NIC_CFG_TSO_IPID_SPLIT_EN_MASK_FIELD 1UL
|
||||
#define NIC_CFG_TSO_IPID_SPLIT_EN_SHIFT 23
|
||||
#define NIC_CFG_IG_VLAN_STRIP_EN (1UL << 24)
|
||||
#define NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD 1UL
|
||||
#define NIC_CFG_IG_VLAN_STRIP_EN_SHIFT 24
|
||||
|
||||
static inline void vnic_set_nic_cfg(u32 *nic_cfg,
|
||||
u8 rss_default_cpu, u8 rss_hash_type,
|
||||
u8 rss_hash_bits, u8 rss_base_cpu,
|
||||
u8 rss_enable, u8 tso_ipid_split_en,
|
||||
u8 ig_vlan_strip_en)
|
||||
{
|
||||
*nic_cfg = (rss_default_cpu & NIC_CFG_RSS_DEFAULT_CPU_MASK_FIELD) |
|
||||
((rss_hash_type & NIC_CFG_RSS_HASH_TYPE_MASK_FIELD)
|
||||
<< NIC_CFG_RSS_HASH_TYPE_SHIFT) |
|
||||
((rss_hash_bits & NIC_CFG_RSS_HASH_BITS_MASK_FIELD)
|
||||
<< NIC_CFG_RSS_HASH_BITS_SHIFT) |
|
||||
((rss_base_cpu & NIC_CFG_RSS_BASE_CPU_MASK_FIELD)
|
||||
<< NIC_CFG_RSS_BASE_CPU_SHIFT) |
|
||||
((rss_enable & NIC_CFG_RSS_ENABLE_MASK_FIELD)
|
||||
<< NIC_CFG_RSS_ENABLE_SHIFT) |
|
||||
((tso_ipid_split_en & NIC_CFG_TSO_IPID_SPLIT_EN_MASK_FIELD)
|
||||
<< NIC_CFG_TSO_IPID_SPLIT_EN_SHIFT) |
|
||||
((ig_vlan_strip_en & NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD)
|
||||
<< NIC_CFG_IG_VLAN_STRIP_EN_SHIFT);
|
||||
}
|
||||
|
||||
#endif /* _VNIC_NIC_H_ */
|
||||
63
drivers/net/enic/vnic_resource.h
Normal file
63
drivers/net/enic/vnic_resource.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_RESOURCE_H_
|
||||
#define _VNIC_RESOURCE_H_
|
||||
|
||||
#define VNIC_RES_MAGIC 0x766E6963L /* 'vnic' */
|
||||
#define VNIC_RES_VERSION 0x00000000L
|
||||
|
||||
/* vNIC resource types */
|
||||
enum vnic_res_type {
|
||||
RES_TYPE_EOL, /* End-of-list */
|
||||
RES_TYPE_WQ, /* Work queues */
|
||||
RES_TYPE_RQ, /* Receive queues */
|
||||
RES_TYPE_CQ, /* Completion queues */
|
||||
RES_TYPE_RSVD1,
|
||||
RES_TYPE_NIC_CFG, /* Enet NIC config registers */
|
||||
RES_TYPE_RSVD2,
|
||||
RES_TYPE_RSVD3,
|
||||
RES_TYPE_RSVD4,
|
||||
RES_TYPE_RSVD5,
|
||||
RES_TYPE_INTR_CTRL, /* Interrupt ctrl table */
|
||||
RES_TYPE_INTR_TABLE, /* MSI/MSI-X Interrupt table */
|
||||
RES_TYPE_INTR_PBA, /* MSI/MSI-X PBA table */
|
||||
RES_TYPE_INTR_PBA_LEGACY, /* Legacy intr status, r2c */
|
||||
RES_TYPE_RSVD6,
|
||||
RES_TYPE_RSVD7,
|
||||
RES_TYPE_DEVCMD, /* Device command region */
|
||||
RES_TYPE_PASS_THRU_PAGE, /* Pass-thru page */
|
||||
|
||||
RES_TYPE_MAX, /* Count of resource types */
|
||||
};
|
||||
|
||||
struct vnic_resource_header {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
};
|
||||
|
||||
struct vnic_resource {
|
||||
u8 type;
|
||||
u8 bar;
|
||||
u8 pad[2];
|
||||
u32 bar_offset;
|
||||
u32 count;
|
||||
};
|
||||
|
||||
#endif /* _VNIC_RESOURCE_H_ */
|
||||
199
drivers/net/enic/vnic_rq.c
Normal file
199
drivers/net/enic/vnic_rq.c
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_rq.h"
|
||||
|
||||
static int vnic_rq_alloc_bufs(struct vnic_rq *rq)
|
||||
{
|
||||
struct vnic_rq_buf *buf;
|
||||
struct vnic_dev *vdev;
|
||||
unsigned int i, j, count = rq->ring.desc_count;
|
||||
unsigned int blks = VNIC_RQ_BUF_BLKS_NEEDED(count);
|
||||
|
||||
vdev = rq->vdev;
|
||||
|
||||
for (i = 0; i < blks; i++) {
|
||||
rq->bufs[i] = kzalloc(VNIC_RQ_BUF_BLK_SZ, GFP_ATOMIC);
|
||||
if (!rq->bufs[i]) {
|
||||
printk(KERN_ERR "Failed to alloc rq_bufs\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < blks; i++) {
|
||||
buf = rq->bufs[i];
|
||||
for (j = 0; j < VNIC_RQ_BUF_BLK_ENTRIES; j++) {
|
||||
buf->index = i * VNIC_RQ_BUF_BLK_ENTRIES + j;
|
||||
buf->desc = (u8 *)rq->ring.descs +
|
||||
rq->ring.desc_size * buf->index;
|
||||
if (buf->index + 1 == count) {
|
||||
buf->next = rq->bufs[0];
|
||||
break;
|
||||
} else if (j + 1 == VNIC_RQ_BUF_BLK_ENTRIES) {
|
||||
buf->next = rq->bufs[i + 1];
|
||||
} else {
|
||||
buf->next = buf + 1;
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rq->to_use = rq->to_clean = rq->bufs[0];
|
||||
rq->buf_index = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_rq_free(struct vnic_rq *rq)
|
||||
{
|
||||
struct vnic_dev *vdev;
|
||||
unsigned int i;
|
||||
|
||||
vdev = rq->vdev;
|
||||
|
||||
vnic_dev_free_desc_ring(vdev, &rq->ring);
|
||||
|
||||
for (i = 0; i < VNIC_RQ_BUF_BLKS_MAX; i++) {
|
||||
kfree(rq->bufs[i]);
|
||||
rq->bufs[i] = NULL;
|
||||
}
|
||||
|
||||
rq->ctrl = NULL;
|
||||
}
|
||||
|
||||
int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index,
|
||||
unsigned int desc_count, unsigned int desc_size)
|
||||
{
|
||||
int err;
|
||||
|
||||
rq->index = index;
|
||||
rq->vdev = vdev;
|
||||
|
||||
rq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_RQ, index);
|
||||
if (!rq->ctrl) {
|
||||
printk(KERN_ERR "Failed to hook RQ[%d] resource\n", index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vnic_rq_disable(rq);
|
||||
|
||||
err = vnic_dev_alloc_desc_ring(vdev, &rq->ring, desc_count, desc_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = vnic_rq_alloc_bufs(rq);
|
||||
if (err) {
|
||||
vnic_rq_free(rq);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset)
|
||||
{
|
||||
u64 paddr;
|
||||
u32 fetch_index;
|
||||
|
||||
paddr = (u64)rq->ring.base_addr | VNIC_PADDR_TARGET;
|
||||
writeq(paddr, &rq->ctrl->ring_base);
|
||||
iowrite32(rq->ring.desc_count, &rq->ctrl->ring_size);
|
||||
iowrite32(cq_index, &rq->ctrl->cq_index);
|
||||
iowrite32(error_interrupt_enable, &rq->ctrl->error_interrupt_enable);
|
||||
iowrite32(error_interrupt_offset, &rq->ctrl->error_interrupt_offset);
|
||||
iowrite32(0, &rq->ctrl->dropped_packet_count);
|
||||
iowrite32(0, &rq->ctrl->error_status);
|
||||
|
||||
/* Use current fetch_index as the ring starting point */
|
||||
fetch_index = ioread32(&rq->ctrl->fetch_index);
|
||||
rq->to_use = rq->to_clean =
|
||||
&rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES]
|
||||
[fetch_index % VNIC_RQ_BUF_BLK_ENTRIES];
|
||||
iowrite32(fetch_index, &rq->ctrl->posted_index);
|
||||
|
||||
rq->buf_index = 0;
|
||||
}
|
||||
|
||||
unsigned int vnic_rq_error_status(struct vnic_rq *rq)
|
||||
{
|
||||
return ioread32(&rq->ctrl->error_status);
|
||||
}
|
||||
|
||||
void vnic_rq_enable(struct vnic_rq *rq)
|
||||
{
|
||||
iowrite32(1, &rq->ctrl->enable);
|
||||
}
|
||||
|
||||
int vnic_rq_disable(struct vnic_rq *rq)
|
||||
{
|
||||
unsigned int wait;
|
||||
|
||||
iowrite32(0, &rq->ctrl->enable);
|
||||
|
||||
/* Wait for HW to ACK disable request */
|
||||
for (wait = 0; wait < 100; wait++) {
|
||||
if (!(ioread32(&rq->ctrl->running)))
|
||||
return 0;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
printk(KERN_ERR "Failed to disable RQ[%d]\n", rq->index);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
void vnic_rq_clean(struct vnic_rq *rq,
|
||||
void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf))
|
||||
{
|
||||
struct vnic_rq_buf *buf;
|
||||
u32 fetch_index;
|
||||
|
||||
BUG_ON(ioread32(&rq->ctrl->enable));
|
||||
|
||||
buf = rq->to_clean;
|
||||
|
||||
while (vnic_rq_desc_used(rq) > 0) {
|
||||
|
||||
(*buf_clean)(rq, buf);
|
||||
|
||||
buf = rq->to_clean = buf->next;
|
||||
rq->ring.desc_avail++;
|
||||
}
|
||||
|
||||
/* Use current fetch_index as the ring starting point */
|
||||
fetch_index = ioread32(&rq->ctrl->fetch_index);
|
||||
rq->to_use = rq->to_clean =
|
||||
&rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES]
|
||||
[fetch_index % VNIC_RQ_BUF_BLK_ENTRIES];
|
||||
iowrite32(fetch_index, &rq->ctrl->posted_index);
|
||||
|
||||
rq->buf_index = 0;
|
||||
|
||||
vnic_dev_clear_desc_ring(&rq->ring);
|
||||
}
|
||||
|
||||
204
drivers/net/enic/vnic_rq.h
Normal file
204
drivers/net/enic/vnic_rq.h
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_RQ_H_
|
||||
#define _VNIC_RQ_H_
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_cq.h"
|
||||
|
||||
/* Receive queue control */
|
||||
struct vnic_rq_ctrl {
|
||||
u64 ring_base; /* 0x00 */
|
||||
u32 ring_size; /* 0x08 */
|
||||
u32 pad0;
|
||||
u32 posted_index; /* 0x10 */
|
||||
u32 pad1;
|
||||
u32 cq_index; /* 0x18 */
|
||||
u32 pad2;
|
||||
u32 enable; /* 0x20 */
|
||||
u32 pad3;
|
||||
u32 running; /* 0x28 */
|
||||
u32 pad4;
|
||||
u32 fetch_index; /* 0x30 */
|
||||
u32 pad5;
|
||||
u32 error_interrupt_enable; /* 0x38 */
|
||||
u32 pad6;
|
||||
u32 error_interrupt_offset; /* 0x40 */
|
||||
u32 pad7;
|
||||
u32 error_status; /* 0x48 */
|
||||
u32 pad8;
|
||||
u32 dropped_packet_count; /* 0x50 */
|
||||
u32 pad9;
|
||||
u32 dropped_packet_count_rc; /* 0x58 */
|
||||
u32 pad10;
|
||||
};
|
||||
|
||||
/* Break the vnic_rq_buf allocations into blocks of 64 entries */
|
||||
#define VNIC_RQ_BUF_BLK_ENTRIES 64
|
||||
#define VNIC_RQ_BUF_BLK_SZ \
|
||||
(VNIC_RQ_BUF_BLK_ENTRIES * sizeof(struct vnic_rq_buf))
|
||||
#define VNIC_RQ_BUF_BLKS_NEEDED(entries) \
|
||||
DIV_ROUND_UP(entries, VNIC_RQ_BUF_BLK_ENTRIES)
|
||||
#define VNIC_RQ_BUF_BLKS_MAX VNIC_RQ_BUF_BLKS_NEEDED(4096)
|
||||
|
||||
struct vnic_rq_buf {
|
||||
struct vnic_rq_buf *next;
|
||||
dma_addr_t dma_addr;
|
||||
void *os_buf;
|
||||
unsigned int os_buf_index;
|
||||
unsigned int len;
|
||||
unsigned int index;
|
||||
void *desc;
|
||||
};
|
||||
|
||||
struct vnic_rq {
|
||||
unsigned int index;
|
||||
struct vnic_dev *vdev;
|
||||
struct vnic_rq_ctrl __iomem *ctrl; /* memory-mapped */
|
||||
struct vnic_dev_ring ring;
|
||||
struct vnic_rq_buf *bufs[VNIC_RQ_BUF_BLKS_MAX];
|
||||
struct vnic_rq_buf *to_use;
|
||||
struct vnic_rq_buf *to_clean;
|
||||
void *os_buf_head;
|
||||
unsigned int buf_index;
|
||||
unsigned int pkts_outstanding;
|
||||
};
|
||||
|
||||
static inline unsigned int vnic_rq_desc_avail(struct vnic_rq *rq)
|
||||
{
|
||||
/* how many does SW own? */
|
||||
return rq->ring.desc_avail;
|
||||
}
|
||||
|
||||
static inline unsigned int vnic_rq_desc_used(struct vnic_rq *rq)
|
||||
{
|
||||
/* how many does HW own? */
|
||||
return rq->ring.desc_count - rq->ring.desc_avail - 1;
|
||||
}
|
||||
|
||||
static inline void *vnic_rq_next_desc(struct vnic_rq *rq)
|
||||
{
|
||||
return rq->to_use->desc;
|
||||
}
|
||||
|
||||
static inline unsigned int vnic_rq_next_index(struct vnic_rq *rq)
|
||||
{
|
||||
return rq->to_use->index;
|
||||
}
|
||||
|
||||
static inline unsigned int vnic_rq_next_buf_index(struct vnic_rq *rq)
|
||||
{
|
||||
return rq->buf_index++;
|
||||
}
|
||||
|
||||
static inline void vnic_rq_post(struct vnic_rq *rq,
|
||||
void *os_buf, unsigned int os_buf_index,
|
||||
dma_addr_t dma_addr, unsigned int len)
|
||||
{
|
||||
struct vnic_rq_buf *buf = rq->to_use;
|
||||
|
||||
buf->os_buf = os_buf;
|
||||
buf->os_buf_index = os_buf_index;
|
||||
buf->dma_addr = dma_addr;
|
||||
buf->len = len;
|
||||
|
||||
buf = buf->next;
|
||||
rq->to_use = buf;
|
||||
rq->ring.desc_avail--;
|
||||
|
||||
/* Move the posted_index every nth descriptor
|
||||
*/
|
||||
|
||||
#ifndef VNIC_RQ_RETURN_RATE
|
||||
#define VNIC_RQ_RETURN_RATE 0xf /* keep 2^n - 1 */
|
||||
#endif
|
||||
|
||||
if ((buf->index & VNIC_RQ_RETURN_RATE) == 0)
|
||||
iowrite32(buf->index, &rq->ctrl->posted_index);
|
||||
}
|
||||
|
||||
static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count)
|
||||
{
|
||||
rq->ring.desc_avail += count;
|
||||
}
|
||||
|
||||
enum desc_return_options {
|
||||
VNIC_RQ_RETURN_DESC,
|
||||
VNIC_RQ_DEFER_RETURN_DESC,
|
||||
};
|
||||
|
||||
static inline void vnic_rq_service(struct vnic_rq *rq,
|
||||
struct cq_desc *cq_desc, u16 completed_index,
|
||||
int desc_return, void (*buf_service)(struct vnic_rq *rq,
|
||||
struct cq_desc *cq_desc, struct vnic_rq_buf *buf,
|
||||
int skipped, void *opaque), void *opaque)
|
||||
{
|
||||
struct vnic_rq_buf *buf;
|
||||
int skipped;
|
||||
|
||||
buf = rq->to_clean;
|
||||
while (1) {
|
||||
|
||||
skipped = (buf->index != completed_index);
|
||||
|
||||
(*buf_service)(rq, cq_desc, buf, skipped, opaque);
|
||||
|
||||
if (desc_return == VNIC_RQ_RETURN_DESC)
|
||||
rq->ring.desc_avail++;
|
||||
|
||||
rq->to_clean = buf->next;
|
||||
|
||||
if (!skipped)
|
||||
break;
|
||||
|
||||
buf = rq->to_clean;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int vnic_rq_fill(struct vnic_rq *rq,
|
||||
int (*buf_fill)(struct vnic_rq *rq))
|
||||
{
|
||||
int err;
|
||||
|
||||
while (vnic_rq_desc_avail(rq) > 1) {
|
||||
|
||||
err = (*buf_fill)(rq);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_rq_free(struct vnic_rq *rq);
|
||||
int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index,
|
||||
unsigned int desc_count, unsigned int desc_size);
|
||||
void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset);
|
||||
unsigned int vnic_rq_error_status(struct vnic_rq *rq);
|
||||
void vnic_rq_enable(struct vnic_rq *rq);
|
||||
int vnic_rq_disable(struct vnic_rq *rq);
|
||||
void vnic_rq_clean(struct vnic_rq *rq,
|
||||
void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf));
|
||||
|
||||
#endif /* _VNIC_RQ_H_ */
|
||||
32
drivers/net/enic/vnic_rss.h
Normal file
32
drivers/net/enic/vnic_rss.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_RSS_H_
|
||||
#define _VNIC_RSS_H_
|
||||
|
||||
/* RSS key array */
|
||||
union vnic_rss_key {
|
||||
struct {
|
||||
u8 b[10];
|
||||
u8 b_pad[6];
|
||||
} key[4];
|
||||
u64 raw[8];
|
||||
};
|
||||
|
||||
/* RSS cpu array */
|
||||
union vnic_rss_cpu {
|
||||
struct {
|
||||
u8 b[4] ;
|
||||
u8 b_pad[4];
|
||||
} cpu[32];
|
||||
u64 raw[32];
|
||||
};
|
||||
|
||||
void vnic_set_rss_key(union vnic_rss_key *rss_key, u8 *key);
|
||||
void vnic_set_rss_cpu(union vnic_rss_cpu *rss_cpu, u8 *cpu);
|
||||
void vnic_get_rss_key(union vnic_rss_key *rss_key, u8 *key);
|
||||
void vnic_get_rss_cpu(union vnic_rss_cpu *rss_cpu, u8 *cpu);
|
||||
|
||||
#endif /* _VNIC_RSS_H_ */
|
||||
70
drivers/net/enic/vnic_stats.h
Normal file
70
drivers/net/enic/vnic_stats.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_STATS_H_
|
||||
#define _VNIC_STATS_H_
|
||||
|
||||
/* Tx statistics */
|
||||
struct vnic_tx_stats {
|
||||
u64 tx_frames_ok;
|
||||
u64 tx_unicast_frames_ok;
|
||||
u64 tx_multicast_frames_ok;
|
||||
u64 tx_broadcast_frames_ok;
|
||||
u64 tx_bytes_ok;
|
||||
u64 tx_unicast_bytes_ok;
|
||||
u64 tx_multicast_bytes_ok;
|
||||
u64 tx_broadcast_bytes_ok;
|
||||
u64 tx_drops;
|
||||
u64 tx_errors;
|
||||
u64 tx_tso;
|
||||
u64 rsvd[16];
|
||||
};
|
||||
|
||||
/* Rx statistics */
|
||||
struct vnic_rx_stats {
|
||||
u64 rx_frames_ok;
|
||||
u64 rx_frames_total;
|
||||
u64 rx_unicast_frames_ok;
|
||||
u64 rx_multicast_frames_ok;
|
||||
u64 rx_broadcast_frames_ok;
|
||||
u64 rx_bytes_ok;
|
||||
u64 rx_unicast_bytes_ok;
|
||||
u64 rx_multicast_bytes_ok;
|
||||
u64 rx_broadcast_bytes_ok;
|
||||
u64 rx_drop;
|
||||
u64 rx_no_bufs;
|
||||
u64 rx_errors;
|
||||
u64 rx_rss;
|
||||
u64 rx_crc_errors;
|
||||
u64 rx_frames_64;
|
||||
u64 rx_frames_127;
|
||||
u64 rx_frames_255;
|
||||
u64 rx_frames_511;
|
||||
u64 rx_frames_1023;
|
||||
u64 rx_frames_1518;
|
||||
u64 rx_frames_to_max;
|
||||
u64 rsvd[16];
|
||||
};
|
||||
|
||||
struct vnic_stats {
|
||||
struct vnic_tx_stats tx;
|
||||
struct vnic_rx_stats rx;
|
||||
};
|
||||
|
||||
#endif /* _VNIC_STATS_H_ */
|
||||
184
drivers/net/enic/vnic_wq.c
Normal file
184
drivers/net/enic/vnic_wq.c
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_wq.h"
|
||||
|
||||
static int vnic_wq_alloc_bufs(struct vnic_wq *wq)
|
||||
{
|
||||
struct vnic_wq_buf *buf;
|
||||
struct vnic_dev *vdev;
|
||||
unsigned int i, j, count = wq->ring.desc_count;
|
||||
unsigned int blks = VNIC_WQ_BUF_BLKS_NEEDED(count);
|
||||
|
||||
vdev = wq->vdev;
|
||||
|
||||
for (i = 0; i < blks; i++) {
|
||||
wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ, GFP_ATOMIC);
|
||||
if (!wq->bufs[i]) {
|
||||
printk(KERN_ERR "Failed to alloc wq_bufs\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < blks; i++) {
|
||||
buf = wq->bufs[i];
|
||||
for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES; j++) {
|
||||
buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES + j;
|
||||
buf->desc = (u8 *)wq->ring.descs +
|
||||
wq->ring.desc_size * buf->index;
|
||||
if (buf->index + 1 == count) {
|
||||
buf->next = wq->bufs[0];
|
||||
break;
|
||||
} else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES) {
|
||||
buf->next = wq->bufs[i + 1];
|
||||
} else {
|
||||
buf->next = buf + 1;
|
||||
buf++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wq->to_use = wq->to_clean = wq->bufs[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_wq_free(struct vnic_wq *wq)
|
||||
{
|
||||
struct vnic_dev *vdev;
|
||||
unsigned int i;
|
||||
|
||||
vdev = wq->vdev;
|
||||
|
||||
vnic_dev_free_desc_ring(vdev, &wq->ring);
|
||||
|
||||
for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) {
|
||||
kfree(wq->bufs[i]);
|
||||
wq->bufs[i] = NULL;
|
||||
}
|
||||
|
||||
wq->ctrl = NULL;
|
||||
}
|
||||
|
||||
int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
|
||||
unsigned int desc_count, unsigned int desc_size)
|
||||
{
|
||||
int err;
|
||||
|
||||
wq->index = index;
|
||||
wq->vdev = vdev;
|
||||
|
||||
wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index);
|
||||
if (!wq->ctrl) {
|
||||
printk(KERN_ERR "Failed to hook WQ[%d] resource\n", index);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vnic_wq_disable(wq);
|
||||
|
||||
err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = vnic_wq_alloc_bufs(wq);
|
||||
if (err) {
|
||||
vnic_wq_free(wq);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset)
|
||||
{
|
||||
u64 paddr;
|
||||
|
||||
paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET;
|
||||
writeq(paddr, &wq->ctrl->ring_base);
|
||||
iowrite32(wq->ring.desc_count, &wq->ctrl->ring_size);
|
||||
iowrite32(0, &wq->ctrl->fetch_index);
|
||||
iowrite32(0, &wq->ctrl->posted_index);
|
||||
iowrite32(cq_index, &wq->ctrl->cq_index);
|
||||
iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable);
|
||||
iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset);
|
||||
iowrite32(0, &wq->ctrl->error_status);
|
||||
}
|
||||
|
||||
unsigned int vnic_wq_error_status(struct vnic_wq *wq)
|
||||
{
|
||||
return ioread32(&wq->ctrl->error_status);
|
||||
}
|
||||
|
||||
void vnic_wq_enable(struct vnic_wq *wq)
|
||||
{
|
||||
iowrite32(1, &wq->ctrl->enable);
|
||||
}
|
||||
|
||||
int vnic_wq_disable(struct vnic_wq *wq)
|
||||
{
|
||||
unsigned int wait;
|
||||
|
||||
iowrite32(0, &wq->ctrl->enable);
|
||||
|
||||
/* Wait for HW to ACK disable request */
|
||||
for (wait = 0; wait < 100; wait++) {
|
||||
if (!(ioread32(&wq->ctrl->running)))
|
||||
return 0;
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
printk(KERN_ERR "Failed to disable WQ[%d]\n", wq->index);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
void vnic_wq_clean(struct vnic_wq *wq,
|
||||
void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf))
|
||||
{
|
||||
struct vnic_wq_buf *buf;
|
||||
|
||||
BUG_ON(ioread32(&wq->ctrl->enable));
|
||||
|
||||
buf = wq->to_clean;
|
||||
|
||||
while (vnic_wq_desc_used(wq) > 0) {
|
||||
|
||||
(*buf_clean)(wq, buf);
|
||||
|
||||
buf = wq->to_clean = buf->next;
|
||||
wq->ring.desc_avail++;
|
||||
}
|
||||
|
||||
wq->to_use = wq->to_clean = wq->bufs[0];
|
||||
|
||||
iowrite32(0, &wq->ctrl->fetch_index);
|
||||
iowrite32(0, &wq->ctrl->posted_index);
|
||||
iowrite32(0, &wq->ctrl->error_status);
|
||||
|
||||
vnic_dev_clear_desc_ring(&wq->ring);
|
||||
}
|
||||
154
drivers/net/enic/vnic_wq.h
Normal file
154
drivers/net/enic/vnic_wq.h
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _VNIC_WQ_H_
|
||||
#define _VNIC_WQ_H_
|
||||
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_cq.h"
|
||||
|
||||
/* Work queue control */
|
||||
struct vnic_wq_ctrl {
|
||||
u64 ring_base; /* 0x00 */
|
||||
u32 ring_size; /* 0x08 */
|
||||
u32 pad0;
|
||||
u32 posted_index; /* 0x10 */
|
||||
u32 pad1;
|
||||
u32 cq_index; /* 0x18 */
|
||||
u32 pad2;
|
||||
u32 enable; /* 0x20 */
|
||||
u32 pad3;
|
||||
u32 running; /* 0x28 */
|
||||
u32 pad4;
|
||||
u32 fetch_index; /* 0x30 */
|
||||
u32 pad5;
|
||||
u32 dca_value; /* 0x38 */
|
||||
u32 pad6;
|
||||
u32 error_interrupt_enable; /* 0x40 */
|
||||
u32 pad7;
|
||||
u32 error_interrupt_offset; /* 0x48 */
|
||||
u32 pad8;
|
||||
u32 error_status; /* 0x50 */
|
||||
u32 pad9;
|
||||
};
|
||||
|
||||
struct vnic_wq_buf {
|
||||
struct vnic_wq_buf *next;
|
||||
dma_addr_t dma_addr;
|
||||
void *os_buf;
|
||||
unsigned int len;
|
||||
unsigned int index;
|
||||
int sop;
|
||||
void *desc;
|
||||
};
|
||||
|
||||
/* Break the vnic_wq_buf allocations into blocks of 64 entries */
|
||||
#define VNIC_WQ_BUF_BLK_ENTRIES 64
|
||||
#define VNIC_WQ_BUF_BLK_SZ \
|
||||
(VNIC_WQ_BUF_BLK_ENTRIES * sizeof(struct vnic_wq_buf))
|
||||
#define VNIC_WQ_BUF_BLKS_NEEDED(entries) \
|
||||
DIV_ROUND_UP(entries, VNIC_WQ_BUF_BLK_ENTRIES)
|
||||
#define VNIC_WQ_BUF_BLKS_MAX VNIC_WQ_BUF_BLKS_NEEDED(4096)
|
||||
|
||||
struct vnic_wq {
|
||||
unsigned int index;
|
||||
struct vnic_dev *vdev;
|
||||
struct vnic_wq_ctrl __iomem *ctrl; /* memory-mapped */
|
||||
struct vnic_dev_ring ring;
|
||||
struct vnic_wq_buf *bufs[VNIC_WQ_BUF_BLKS_MAX];
|
||||
struct vnic_wq_buf *to_use;
|
||||
struct vnic_wq_buf *to_clean;
|
||||
unsigned int pkts_outstanding;
|
||||
};
|
||||
|
||||
static inline unsigned int vnic_wq_desc_avail(struct vnic_wq *wq)
|
||||
{
|
||||
/* how many does SW own? */
|
||||
return wq->ring.desc_avail;
|
||||
}
|
||||
|
||||
static inline unsigned int vnic_wq_desc_used(struct vnic_wq *wq)
|
||||
{
|
||||
/* how many does HW own? */
|
||||
return wq->ring.desc_count - wq->ring.desc_avail - 1;
|
||||
}
|
||||
|
||||
static inline void *vnic_wq_next_desc(struct vnic_wq *wq)
|
||||
{
|
||||
return wq->to_use->desc;
|
||||
}
|
||||
|
||||
static inline void vnic_wq_post(struct vnic_wq *wq,
|
||||
void *os_buf, dma_addr_t dma_addr,
|
||||
unsigned int len, int sop, int eop)
|
||||
{
|
||||
struct vnic_wq_buf *buf = wq->to_use;
|
||||
|
||||
buf->sop = sop;
|
||||
buf->os_buf = eop ? os_buf : NULL;
|
||||
buf->dma_addr = dma_addr;
|
||||
buf->len = len;
|
||||
|
||||
buf = buf->next;
|
||||
if (eop)
|
||||
iowrite32(buf->index, &wq->ctrl->posted_index);
|
||||
wq->to_use = buf;
|
||||
|
||||
wq->ring.desc_avail--;
|
||||
}
|
||||
|
||||
static inline void vnic_wq_service(struct vnic_wq *wq,
|
||||
struct cq_desc *cq_desc, u16 completed_index,
|
||||
void (*buf_service)(struct vnic_wq *wq,
|
||||
struct cq_desc *cq_desc, struct vnic_wq_buf *buf, void *opaque),
|
||||
void *opaque)
|
||||
{
|
||||
struct vnic_wq_buf *buf;
|
||||
|
||||
buf = wq->to_clean;
|
||||
while (1) {
|
||||
|
||||
(*buf_service)(wq, cq_desc, buf, opaque);
|
||||
|
||||
wq->ring.desc_avail++;
|
||||
|
||||
wq->to_clean = buf->next;
|
||||
|
||||
if (buf->index == completed_index)
|
||||
break;
|
||||
|
||||
buf = wq->to_clean;
|
||||
}
|
||||
}
|
||||
|
||||
void vnic_wq_free(struct vnic_wq *wq);
|
||||
int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
|
||||
unsigned int desc_count, unsigned int desc_size);
|
||||
void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index,
|
||||
unsigned int error_interrupt_enable,
|
||||
unsigned int error_interrupt_offset);
|
||||
unsigned int vnic_wq_error_status(struct vnic_wq *wq);
|
||||
void vnic_wq_enable(struct vnic_wq *wq);
|
||||
int vnic_wq_disable(struct vnic_wq *wq);
|
||||
void vnic_wq_clean(struct vnic_wq *wq,
|
||||
void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf));
|
||||
|
||||
#endif /* _VNIC_WQ_H_ */
|
||||
98
drivers/net/enic/wq_enet_desc.h
Normal file
98
drivers/net/enic/wq_enet_desc.h
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _WQ_ENET_DESC_H_
|
||||
#define _WQ_ENET_DESC_H_
|
||||
|
||||
/* Ethernet work queue descriptor: 16B */
|
||||
struct wq_enet_desc {
|
||||
__le64 address;
|
||||
__le16 length;
|
||||
__le16 mss_loopback;
|
||||
__le16 header_length_flags;
|
||||
__le16 vlan_tag;
|
||||
};
|
||||
|
||||
#define WQ_ENET_ADDR_BITS 64
|
||||
#define WQ_ENET_LEN_BITS 14
|
||||
#define WQ_ENET_LEN_MASK ((1 << WQ_ENET_LEN_BITS) - 1)
|
||||
#define WQ_ENET_MSS_BITS 14
|
||||
#define WQ_ENET_MSS_MASK ((1 << WQ_ENET_MSS_BITS) - 1)
|
||||
#define WQ_ENET_MSS_SHIFT 2
|
||||
#define WQ_ENET_LOOPBACK_SHIFT 1
|
||||
#define WQ_ENET_HDRLEN_BITS 10
|
||||
#define WQ_ENET_HDRLEN_MASK ((1 << WQ_ENET_HDRLEN_BITS) - 1)
|
||||
#define WQ_ENET_FLAGS_OM_BITS 2
|
||||
#define WQ_ENET_FLAGS_OM_MASK ((1 << WQ_ENET_FLAGS_OM_BITS) - 1)
|
||||
#define WQ_ENET_FLAGS_EOP_SHIFT 12
|
||||
#define WQ_ENET_FLAGS_CQ_ENTRY_SHIFT 13
|
||||
#define WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT 14
|
||||
#define WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT 15
|
||||
|
||||
#define WQ_ENET_OFFLOAD_MODE_CSUM 0
|
||||
#define WQ_ENET_OFFLOAD_MODE_RESERVED 1
|
||||
#define WQ_ENET_OFFLOAD_MODE_CSUM_L4 2
|
||||
#define WQ_ENET_OFFLOAD_MODE_TSO 3
|
||||
|
||||
static inline void wq_enet_desc_enc(struct wq_enet_desc *desc,
|
||||
u64 address, u16 length, u16 mss, u16 header_length,
|
||||
u8 offload_mode, u8 eop, u8 cq_entry, u8 fcoe_encap,
|
||||
u8 vlan_tag_insert, u16 vlan_tag, u8 loopback)
|
||||
{
|
||||
desc->address = cpu_to_le64(address);
|
||||
desc->length = cpu_to_le16(length & WQ_ENET_LEN_MASK);
|
||||
desc->mss_loopback = cpu_to_le16((mss & WQ_ENET_MSS_MASK) <<
|
||||
WQ_ENET_MSS_SHIFT | (loopback & 1) << WQ_ENET_LOOPBACK_SHIFT);
|
||||
desc->header_length_flags = cpu_to_le16(
|
||||
(header_length & WQ_ENET_HDRLEN_MASK) |
|
||||
(offload_mode & WQ_ENET_FLAGS_OM_MASK) << WQ_ENET_HDRLEN_BITS |
|
||||
(eop & 1) << WQ_ENET_FLAGS_EOP_SHIFT |
|
||||
(cq_entry & 1) << WQ_ENET_FLAGS_CQ_ENTRY_SHIFT |
|
||||
(fcoe_encap & 1) << WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT |
|
||||
(vlan_tag_insert & 1) << WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT);
|
||||
desc->vlan_tag = cpu_to_le16(vlan_tag);
|
||||
}
|
||||
|
||||
static inline void wq_enet_desc_dec(struct wq_enet_desc *desc,
|
||||
u64 *address, u16 *length, u16 *mss, u16 *header_length,
|
||||
u8 *offload_mode, u8 *eop, u8 *cq_entry, u8 *fcoe_encap,
|
||||
u8 *vlan_tag_insert, u16 *vlan_tag, u8 *loopback)
|
||||
{
|
||||
*address = le64_to_cpu(desc->address);
|
||||
*length = le16_to_cpu(desc->length) & WQ_ENET_LEN_MASK;
|
||||
*mss = (le16_to_cpu(desc->mss_loopback) >> WQ_ENET_MSS_SHIFT) &
|
||||
WQ_ENET_MSS_MASK;
|
||||
*loopback = (u8)((le16_to_cpu(desc->mss_loopback) >>
|
||||
WQ_ENET_LOOPBACK_SHIFT) & 1);
|
||||
*header_length = le16_to_cpu(desc->header_length_flags) &
|
||||
WQ_ENET_HDRLEN_MASK;
|
||||
*offload_mode = (u8)((le16_to_cpu(desc->header_length_flags) >>
|
||||
WQ_ENET_HDRLEN_BITS) & WQ_ENET_FLAGS_OM_MASK);
|
||||
*eop = (u8)((le16_to_cpu(desc->header_length_flags) >>
|
||||
WQ_ENET_FLAGS_EOP_SHIFT) & 1);
|
||||
*cq_entry = (u8)((le16_to_cpu(desc->header_length_flags) >>
|
||||
WQ_ENET_FLAGS_CQ_ENTRY_SHIFT) & 1);
|
||||
*fcoe_encap = (u8)((le16_to_cpu(desc->header_length_flags) >>
|
||||
WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT) & 1);
|
||||
*vlan_tag_insert = (u8)((le16_to_cpu(desc->header_length_flags) >>
|
||||
WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT) & 1);
|
||||
*vlan_tag = le16_to_cpu(desc->vlan_tag);
|
||||
}
|
||||
|
||||
#endif /* _WQ_ENET_DESC_H_ */
|
||||
|
|
@ -431,7 +431,7 @@ static void getlinktype(struct net_device *dev);
|
|||
static void getlinkstatus(struct net_device *dev);
|
||||
static void netdev_timer(unsigned long data);
|
||||
static void reset_timer(unsigned long data);
|
||||
static void tx_timeout(struct net_device *dev);
|
||||
static void fealnx_tx_timeout(struct net_device *dev);
|
||||
static void init_ring(struct net_device *dev);
|
||||
static int start_tx(struct sk_buff *skb, struct net_device *dev);
|
||||
static irqreturn_t intr_handler(int irq, void *dev_instance);
|
||||
|
|
@ -658,7 +658,7 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev,
|
|||
dev->set_multicast_list = &set_rx_mode;
|
||||
dev->do_ioctl = &mii_ioctl;
|
||||
dev->ethtool_ops = &netdev_ethtool_ops;
|
||||
dev->tx_timeout = &tx_timeout;
|
||||
dev->tx_timeout = &fealnx_tx_timeout;
|
||||
dev->watchdog_timeo = TX_TIMEOUT;
|
||||
|
||||
err = register_netdev(dev);
|
||||
|
|
@ -1198,7 +1198,7 @@ static void reset_timer(unsigned long data)
|
|||
}
|
||||
|
||||
|
||||
static void tx_timeout(struct net_device *dev)
|
||||
static void fealnx_tx_timeout(struct net_device *dev)
|
||||
{
|
||||
struct netdev_private *np = netdev_priv(dev);
|
||||
void __iomem *ioaddr = np->mem;
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_i
|
|||
int err;
|
||||
int i;
|
||||
|
||||
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
|
||||
bus = mdiobus_alloc();
|
||||
if (bus == NULL)
|
||||
return -ENOMEM;
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
|
|
@ -127,7 +127,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_i
|
|||
snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start);
|
||||
bus->priv = priv;
|
||||
|
||||
bus->dev = dev;
|
||||
bus->parent = dev;
|
||||
dev_set_drvdata(dev, bus);
|
||||
|
||||
/* set MII speed */
|
||||
|
|
@ -150,7 +150,7 @@ static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_i
|
|||
irq_dispose_mapping(bus->irq[i]);
|
||||
kfree(bus->irq);
|
||||
kfree(priv);
|
||||
kfree(bus);
|
||||
mdiobus_free(bus);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -171,7 +171,7 @@ static int mpc52xx_fec_mdio_remove(struct of_device *of)
|
|||
irq_dispose_mapping(bus->irq[i]);
|
||||
kfree(priv);
|
||||
kfree(bus->irq);
|
||||
kfree(bus);
|
||||
mdiobus_free(bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ enum {
|
|||
NvRegMSIXIrqStatus = 0x3f0,
|
||||
|
||||
NvRegPowerState2 = 0x600,
|
||||
#define NVREG_POWERSTATE2_POWERUP_MASK 0x0F11
|
||||
#define NVREG_POWERSTATE2_POWERUP_MASK 0x0F15
|
||||
#define NVREG_POWERSTATE2_POWERUP_REV_A3 0x0001
|
||||
#define NVREG_POWERSTATE2_PHY_RESET 0x0004
|
||||
};
|
||||
|
|
@ -5643,6 +5643,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
|
|||
dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff;
|
||||
dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff;
|
||||
writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll);
|
||||
printk(KERN_DEBUG "nv_probe: set workaround bit for reversed mac addr\n");
|
||||
}
|
||||
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
|
||||
|
||||
|
|
@ -5890,14 +5891,12 @@ static void nv_restore_phy(struct net_device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static void __devexit nv_remove(struct pci_dev *pci_dev)
|
||||
static void nv_restore_mac_addr(struct pci_dev *pci_dev)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pci_dev);
|
||||
struct fe_priv *np = netdev_priv(dev);
|
||||
u8 __iomem *base = get_hwbase(dev);
|
||||
|
||||
unregister_netdev(dev);
|
||||
|
||||
/* special op: write back the misordered MAC address - otherwise
|
||||
* the next nv_probe would see a wrong address.
|
||||
*/
|
||||
|
|
@ -5905,6 +5904,15 @@ static void __devexit nv_remove(struct pci_dev *pci_dev)
|
|||
writel(np->orig_mac[1], base + NvRegMacAddrB);
|
||||
writel(readl(base + NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV,
|
||||
base + NvRegTransmitPoll);
|
||||
}
|
||||
|
||||
static void __devexit nv_remove(struct pci_dev *pci_dev)
|
||||
{
|
||||
struct net_device *dev = pci_get_drvdata(pci_dev);
|
||||
|
||||
unregister_netdev(dev);
|
||||
|
||||
nv_restore_mac_addr(pci_dev);
|
||||
|
||||
/* restore any phy related changes */
|
||||
nv_restore_phy(dev);
|
||||
|
|
@ -5975,6 +5983,8 @@ static void nv_shutdown(struct pci_dev *pdev)
|
|||
if (netif_running(dev))
|
||||
nv_close(dev);
|
||||
|
||||
nv_restore_mac_addr(pdev);
|
||||
|
||||
pci_disable_device(pdev);
|
||||
if (system_state == SYSTEM_POWER_OFF) {
|
||||
if (pci_enable_wake(pdev, PCI_D3cold, np->wolenabled))
|
||||
|
|
|
|||
|
|
@ -664,23 +664,6 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
static int fs_request_irq(struct net_device *dev, int irq, const char *name,
|
||||
irq_handler_t irqf)
|
||||
{
|
||||
struct fs_enet_private *fep = netdev_priv(dev);
|
||||
|
||||
(*fep->ops->pre_request_irq)(dev, irq);
|
||||
return request_irq(irq, irqf, IRQF_SHARED, name, dev);
|
||||
}
|
||||
|
||||
static void fs_free_irq(struct net_device *dev, int irq)
|
||||
{
|
||||
struct fs_enet_private *fep = netdev_priv(dev);
|
||||
|
||||
free_irq(irq, dev);
|
||||
(*fep->ops->post_free_irq)(dev, irq);
|
||||
}
|
||||
|
||||
static void fs_timeout(struct net_device *dev)
|
||||
{
|
||||
struct fs_enet_private *fep = netdev_priv(dev);
|
||||
|
|
@ -800,7 +783,8 @@ static int fs_enet_open(struct net_device *dev)
|
|||
napi_enable(&fep->napi);
|
||||
|
||||
/* Install our interrupt handler. */
|
||||
r = fs_request_irq(dev, fep->interrupt, "fs_enet-mac", fs_enet_interrupt);
|
||||
r = request_irq(fep->interrupt, fs_enet_interrupt, IRQF_SHARED,
|
||||
"fs_enet-mac", dev);
|
||||
if (r != 0) {
|
||||
printk(KERN_ERR DRV_MODULE_NAME
|
||||
": %s Could not allocate FS_ENET IRQ!", dev->name);
|
||||
|
|
@ -842,7 +826,7 @@ static int fs_enet_close(struct net_device *dev)
|
|||
/* release any irqs */
|
||||
phy_disconnect(fep->phydev);
|
||||
fep->phydev = NULL;
|
||||
fs_free_irq(dev, fep->interrupt);
|
||||
free_irq(fep->interrupt, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,6 @@ struct fs_ops {
|
|||
void (*adjust_link)(struct net_device *dev);
|
||||
void (*restart)(struct net_device *dev);
|
||||
void (*stop)(struct net_device *dev);
|
||||
void (*pre_request_irq)(struct net_device *dev, int irq);
|
||||
void (*post_free_irq)(struct net_device *dev, int irq);
|
||||
void (*napi_clear_rx_event)(struct net_device *dev);
|
||||
void (*napi_enable_rx)(struct net_device *dev);
|
||||
void (*napi_disable_rx)(struct net_device *dev);
|
||||
|
|
|
|||
|
|
@ -421,16 +421,6 @@ static void stop(struct net_device *dev)
|
|||
fs_cleanup_bds(dev);
|
||||
}
|
||||
|
||||
static void pre_request_irq(struct net_device *dev, int irq)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void post_free_irq(struct net_device *dev, int irq)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void napi_clear_rx_event(struct net_device *dev)
|
||||
{
|
||||
struct fs_enet_private *fep = netdev_priv(dev);
|
||||
|
|
@ -540,8 +530,6 @@ const struct fs_ops fs_fcc_ops = {
|
|||
.set_multicast_list = set_multicast_list,
|
||||
.restart = restart,
|
||||
.stop = stop,
|
||||
.pre_request_irq = pre_request_irq,
|
||||
.post_free_irq = post_free_irq,
|
||||
.napi_clear_rx_event = napi_clear_rx_event,
|
||||
.napi_enable_rx = napi_enable_rx,
|
||||
.napi_disable_rx = napi_disable_rx,
|
||||
|
|
|
|||
|
|
@ -313,11 +313,7 @@ static void restart(struct net_device *dev)
|
|||
* Clear any outstanding interrupt.
|
||||
*/
|
||||
FW(fecp, ievent, 0xffc0);
|
||||
#ifndef CONFIG_PPC_MERGE
|
||||
FW(fecp, ivec, (fep->interrupt / 2) << 29);
|
||||
#else
|
||||
FW(fecp, ivec, (virq_to_hw(fep->interrupt) / 2) << 29);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* adjust to speed (only for DUET & RMII)
|
||||
|
|
@ -413,30 +409,6 @@ static void stop(struct net_device *dev)
|
|||
}
|
||||
}
|
||||
|
||||
static void pre_request_irq(struct net_device *dev, int irq)
|
||||
{
|
||||
#ifndef CONFIG_PPC_MERGE
|
||||
immap_t *immap = fs_enet_immap;
|
||||
u32 siel;
|
||||
|
||||
/* SIU interrupt */
|
||||
if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) {
|
||||
|
||||
siel = in_be32(&immap->im_siu_conf.sc_siel);
|
||||
if ((irq & 1) == 0)
|
||||
siel |= (0x80000000 >> irq);
|
||||
else
|
||||
siel &= ~(0x80000000 >> (irq & ~1));
|
||||
out_be32(&immap->im_siu_conf.sc_siel, siel);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void post_free_irq(struct net_device *dev, int irq)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void napi_clear_rx_event(struct net_device *dev)
|
||||
{
|
||||
struct fs_enet_private *fep = netdev_priv(dev);
|
||||
|
|
@ -529,8 +501,6 @@ const struct fs_ops fs_fec_ops = {
|
|||
.set_multicast_list = set_multicast_list,
|
||||
.restart = restart,
|
||||
.stop = stop,
|
||||
.pre_request_irq = pre_request_irq,
|
||||
.post_free_irq = post_free_irq,
|
||||
.napi_clear_rx_event = napi_clear_rx_event,
|
||||
.napi_enable_rx = napi_enable_rx,
|
||||
.napi_disable_rx = napi_disable_rx,
|
||||
|
|
|
|||
|
|
@ -377,30 +377,6 @@ static void stop(struct net_device *dev)
|
|||
fs_cleanup_bds(dev);
|
||||
}
|
||||
|
||||
static void pre_request_irq(struct net_device *dev, int irq)
|
||||
{
|
||||
#ifndef CONFIG_PPC_MERGE
|
||||
immap_t *immap = fs_enet_immap;
|
||||
u32 siel;
|
||||
|
||||
/* SIU interrupt */
|
||||
if (irq >= SIU_IRQ0 && irq < SIU_LEVEL7) {
|
||||
|
||||
siel = in_be32(&immap->im_siu_conf.sc_siel);
|
||||
if ((irq & 1) == 0)
|
||||
siel |= (0x80000000 >> irq);
|
||||
else
|
||||
siel &= ~(0x80000000 >> (irq & ~1));
|
||||
out_be32(&immap->im_siu_conf.sc_siel, siel);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void post_free_irq(struct net_device *dev, int irq)
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
static void napi_clear_rx_event(struct net_device *dev)
|
||||
{
|
||||
struct fs_enet_private *fep = netdev_priv(dev);
|
||||
|
|
@ -494,8 +470,6 @@ const struct fs_ops fs_scc_ops = {
|
|||
.set_multicast_list = set_multicast_list,
|
||||
.restart = restart,
|
||||
.stop = stop,
|
||||
.pre_request_irq = pre_request_irq,
|
||||
.post_free_irq = post_free_irq,
|
||||
.napi_clear_rx_event = napi_clear_rx_event,
|
||||
.napi_enable_rx = napi_enable_rx,
|
||||
.napi_disable_rx = napi_disable_rx,
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
|
|||
if (!strcmp(np->type, "ethernet-phy"))
|
||||
add_phy(new_bus, np);
|
||||
|
||||
new_bus->dev = &ofdev->dev;
|
||||
new_bus->parent = &ofdev->dev;
|
||||
dev_set_drvdata(&ofdev->dev, new_bus);
|
||||
|
||||
ret = mdiobus_register(new_bus);
|
||||
|
|
@ -218,9 +218,9 @@ out_free_irqs:
|
|||
out_unmap_regs:
|
||||
iounmap(bitbang->dir);
|
||||
out_free_bus:
|
||||
kfree(new_bus);
|
||||
out_free_priv:
|
||||
free_mdio_bitbang(new_bus);
|
||||
out_free_priv:
|
||||
kfree(bitbang);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -231,12 +231,11 @@ static int fs_enet_mdio_remove(struct of_device *ofdev)
|
|||
struct bb_info *bitbang = bus->priv;
|
||||
|
||||
mdiobus_unregister(bus);
|
||||
free_mdio_bitbang(bus);
|
||||
dev_set_drvdata(&ofdev->dev, NULL);
|
||||
kfree(bus->irq);
|
||||
free_mdio_bitbang(bus);
|
||||
iounmap(bitbang->dir);
|
||||
kfree(bitbang);
|
||||
kfree(bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
|
|||
struct fec_info *fec;
|
||||
int ret = -ENOMEM, i;
|
||||
|
||||
new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
|
||||
new_bus = mdiobus_alloc();
|
||||
if (!new_bus)
|
||||
goto out;
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
|
|||
if (!strcmp(np->type, "ethernet-phy"))
|
||||
add_phy(new_bus, np);
|
||||
|
||||
new_bus->dev = &ofdev->dev;
|
||||
new_bus->parent = &ofdev->dev;
|
||||
dev_set_drvdata(&ofdev->dev, new_bus);
|
||||
|
||||
ret = mdiobus_register(new_bus);
|
||||
|
|
@ -190,7 +190,7 @@ out_res:
|
|||
out_fec:
|
||||
kfree(fec);
|
||||
out_mii:
|
||||
kfree(new_bus);
|
||||
mdiobus_free(new_bus);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -205,7 +205,7 @@ static int fs_enet_mdio_remove(struct of_device *ofdev)
|
|||
kfree(bus->irq);
|
||||
iounmap(fec->fecp);
|
||||
kfree(fec);
|
||||
kfree(bus);
|
||||
mdiobus_free(bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -339,6 +339,9 @@ static int gfar_probe(struct platform_device *pdev)
|
|||
/* Enable most messages by default */
|
||||
priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
|
||||
|
||||
/* Carrier starts down, phylib will bring it up */
|
||||
netif_carrier_off(dev);
|
||||
|
||||
err = register_netdev(dev);
|
||||
|
||||
if (err) {
|
||||
|
|
|
|||
|
|
@ -136,12 +136,12 @@ static int gfar_mdio_reset(struct mii_bus *bus)
|
|||
|
||||
/* Wait until the bus is free */
|
||||
while ((gfar_read(®s->miimind) & MIIMIND_BUSY) &&
|
||||
timeout--)
|
||||
--timeout)
|
||||
cpu_relax();
|
||||
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
|
||||
if(timeout <= 0) {
|
||||
if(timeout == 0) {
|
||||
printk(KERN_ERR "%s: The MII Bus is stuck!\n",
|
||||
bus->name);
|
||||
return -EBUSY;
|
||||
|
|
@ -164,8 +164,7 @@ static int gfar_mdio_probe(struct device *dev)
|
|||
if (NULL == dev)
|
||||
return -EINVAL;
|
||||
|
||||
new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
|
||||
|
||||
new_bus = mdiobus_alloc();
|
||||
if (NULL == new_bus)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -196,7 +195,7 @@ static int gfar_mdio_probe(struct device *dev)
|
|||
|
||||
new_bus->irq = pdata->irq;
|
||||
|
||||
new_bus->dev = dev;
|
||||
new_bus->parent = dev;
|
||||
dev_set_drvdata(dev, new_bus);
|
||||
|
||||
/*
|
||||
|
|
@ -211,19 +210,21 @@ static int gfar_mdio_probe(struct device *dev)
|
|||
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;
|
||||
err = get_phy_id(new_bus, i, &phy_id);
|
||||
if (err)
|
||||
goto bus_register_fail;
|
||||
|
||||
if (phy_id == 0xffffffff)
|
||||
break;
|
||||
}
|
||||
|
||||
/* The bus is full. We don't support using 31 PHYs, sorry */
|
||||
if (i == 0)
|
||||
return -EBUSY;
|
||||
if (i == 0) {
|
||||
err = -EBUSY;
|
||||
|
||||
goto bus_register_fail;
|
||||
}
|
||||
|
||||
gfar_write(&enet_regs->tbipa, i);
|
||||
|
||||
|
|
@ -240,7 +241,7 @@ static int gfar_mdio_probe(struct device *dev)
|
|||
bus_register_fail:
|
||||
iounmap(regs);
|
||||
reg_map_fail:
|
||||
kfree(new_bus);
|
||||
mdiobus_free(new_bus);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -256,7 +257,7 @@ static int gfar_mdio_remove(struct device *dev)
|
|||
|
||||
iounmap((void __iomem *)bus->priv);
|
||||
bus->priv = NULL;
|
||||
kfree(bus);
|
||||
mdiobus_free(bus);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ static int __init do_hpp_probe(struct net_device *dev)
|
|||
#ifndef MODULE
|
||||
struct net_device * __init hp_plus_probe(int unit)
|
||||
{
|
||||
struct net_device *dev = alloc_ei_netdev();
|
||||
struct net_device *dev = alloc_eip_netdev();
|
||||
int err;
|
||||
|
||||
if (!dev)
|
||||
|
|
@ -284,7 +284,7 @@ hpp_open(struct net_device *dev)
|
|||
int option_reg;
|
||||
int retval;
|
||||
|
||||
if ((retval = request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))) {
|
||||
if ((retval = request_irq(dev->irq, eip_interrupt, 0, dev->name, dev))) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -302,7 +302,7 @@ hpp_open(struct net_device *dev)
|
|||
/* Select the operational page. */
|
||||
outw(Perf_Page, ioaddr + HP_PAGING);
|
||||
|
||||
ei_open(dev);
|
||||
eip_open(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -313,7 +313,7 @@ hpp_close(struct net_device *dev)
|
|||
int option_reg = inw(ioaddr + HPP_OPTION);
|
||||
|
||||
free_irq(dev->irq, dev);
|
||||
ei_close(dev);
|
||||
eip_close(dev);
|
||||
outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
|
||||
ioaddr + HPP_OPTION);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
config IBM_NEW_EMAC
|
||||
tristate "IBM EMAC Ethernet support"
|
||||
depends on PPC_DCR && PPC_MERGE
|
||||
depends on PPC_DCR
|
||||
select CRC32
|
||||
help
|
||||
This driver supports the IBM EMAC family of Ethernet controllers
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue