diff options
Diffstat (limited to 'drivers/net')
34 files changed, 2007 insertions, 211 deletions
diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c index a1d4188c430..e7810b74f39 100644 --- a/drivers/net/arm/ks8695net.c +++ b/drivers/net/arm/ks8695net.c @@ -449,11 +449,10 @@ ks8695_rx_irq(int irq, void *dev_id) } /** - * ks8695_rx - Receive packets called by NAPI poll method + * ks8695_rx - Receive packets called by NAPI poll method * @ksp: Private data for the KS8695 Ethernet - * @budget: The max packets would be receive + * @budget: Number of packets allowed to process */ - static int ks8695_rx(struct ks8695_priv *ksp, int budget) { struct net_device *ndev = ksp->ndev; @@ -461,7 +460,6 @@ static int ks8695_rx(struct ks8695_priv *ksp, int budget) int buff_n; u32 flags; int pktlen; - int last_rx_processed = -1; int received = 0; buff_n = ksp->next_rx_desc_read; @@ -471,6 +469,7 @@ static int ks8695_rx(struct ks8695_priv *ksp, int budget) cpu_to_le32(RDES_OWN)))) { rmb(); flags = le32_to_cpu(ksp->rx_ring[buff_n].status); + /* Found an SKB which we own, this means we * received a packet */ @@ -533,23 +532,18 @@ rx_failure: ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN); rx_finished: received++; - /* And note this as processed so we can start - * from here next time - */ - last_rx_processed = buff_n; buff_n = (buff_n + 1) & MAX_RX_DESC_MASK; - /*And note which RX descriptor we last did */ - if (likely(last_rx_processed != -1)) - ksp->next_rx_desc_read = - (last_rx_processed + 1) & - MAX_RX_DESC_MASK; } + + /* And note which RX descriptor we last did */ + ksp->next_rx_desc_read = buff_n; + /* And refill the buffers */ ks8695_refill_rxbuffers(ksp); - /* Kick the RX DMA engine, in case it became - * suspended */ + /* Kick the RX DMA engine, in case it became suspended */ ks8695_writereg(ksp, KS8695_DRSC, 0); + return received; } diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index c59215361f4..50e6259b50e 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c @@ -673,7 +673,7 @@ int be_cmd_mccq_create(struct be_adapter *adapter, be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, OPCODE_COMMON_MCC_CREATE, sizeof(*req)); - req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); + req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1); AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt, diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index ed785a30e98..6c042a72d6c 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -893,7 +893,6 @@ static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp) u16 prod; u16 cons; - barrier(); /* Tell compiler that prod and cons can change */ prod = fp->tx_bd_prod; cons = fp->tx_bd_cons; @@ -963,7 +962,7 @@ static int bnx2x_tx_int(struct bnx2x_fastpath *fp) * start_xmit() will miss it and cause the queue to be stopped * forever. */ - smp_wmb(); + smp_mb(); /* TBD need a thresh? */ if (unlikely(netif_tx_queue_stopped(txq))) { @@ -11429,9 +11428,12 @@ static netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(bnx2x_tx_avail(fp) < MAX_SKB_FRAGS + 3)) { netif_tx_stop_queue(txq); - /* We want bnx2x_tx_int to "see" the updated tx_bd_prod - if we put Tx into XOFF state. */ + + /* paired memory barrier is in bnx2x_tx_int(), we have to keep + * ordering of set_bit() in netif_tx_stop_queue() and read of + * fp->bd_tx_cons */ smp_mb(); + fp->eth_q_stats.driver_xoff++; if (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3) netif_tx_wake_queue(txq); diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 8bd086aee56..2b8edd2efbf 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -29,10 +29,6 @@ * PHY layer usage */ -/** Pending Items in this driver: - * 1. Use Linux cache infrastcture for DMA'ed memory (dma_xxx functions) - */ - #include <linux/module.h> #include <linux/kernel.h> #include <linux/sched.h> @@ -504,12 +500,6 @@ static unsigned long mdio_max_freq; /* Cache macros - Packet buffers would be from skb pool which is cached */ #define EMAC_VIRT_NOCACHE(addr) (addr) -#define EMAC_CACHE_INVALIDATE(addr, size) \ - dma_cache_maint((void *)addr, size, DMA_FROM_DEVICE) -#define EMAC_CACHE_WRITEBACK(addr, size) \ - dma_cache_maint((void *)addr, size, DMA_TO_DEVICE) -#define EMAC_CACHE_WRITEBACK_INVALIDATE(addr, size) \ - dma_cache_maint((void *)addr, size, DMA_BIDIRECTIONAL) /* DM644x does not have BD's in cached memory - so no cache functions */ #define BD_CACHE_INVALIDATE(addr, size) @@ -1235,6 +1225,10 @@ static void emac_txch_teardown(struct emac_priv *priv, u32 ch) if (1 == txch->queue_active) { curr_bd = txch->active_queue_head; while (curr_bd != NULL) { + dma_unmap_single(emac_dev, curr_bd->buff_ptr, + curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE, + DMA_TO_DEVICE); + emac_net_tx_complete(priv, (void __force *) &curr_bd->buf_token, 1, ch); if (curr_bd != txch->active_queue_tail) @@ -1327,6 +1321,11 @@ static int emac_tx_bdproc(struct emac_priv *priv, u32 ch, u32 budget) txch->queue_active = 0; /* end of queue */ } } + + dma_unmap_single(emac_dev, curr_bd->buff_ptr, + curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE, + DMA_TO_DEVICE); + *tx_complete_ptr = (u32) curr_bd->buf_token; ++tx_complete_ptr; ++tx_complete_cnt; @@ -1387,8 +1386,8 @@ static int emac_send(struct emac_priv *priv, struct emac_netpktobj *pkt, u32 ch) txch->bd_pool_head = curr_bd->next; curr_bd->buf_token = buf_list->buf_token; - /* FIXME buff_ptr = dma_map_single(... data_ptr ...) */ - curr_bd->buff_ptr = virt_to_phys(buf_list->data_ptr); + curr_bd->buff_ptr = dma_map_single(&priv->ndev->dev, buf_list->data_ptr, + buf_list->length, DMA_TO_DEVICE); curr_bd->off_b_len = buf_list->length; curr_bd->h_next = 0; curr_bd->next = NULL; @@ -1468,7 +1467,6 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev) tx_buf.length = skb->len; tx_buf.buf_token = (void *)skb; tx_buf.data_ptr = skb->data; - EMAC_CACHE_WRITEBACK((unsigned long)skb->data, skb->len); ndev->trans_start = jiffies; ret_code = emac_send(priv, &tx_packet, EMAC_DEF_TX_CH); if (unlikely(ret_code != 0)) { @@ -1543,7 +1541,6 @@ static void *emac_net_alloc_rx_buf(struct emac_priv *priv, int buf_size, p_skb->dev = ndev; skb_reserve(p_skb, NET_IP_ALIGN); *data_token = (void *) p_skb; - EMAC_CACHE_WRITEBACK_INVALIDATE((unsigned long)p_skb->data, buf_size); return p_skb->data; } @@ -1612,8 +1609,8 @@ static int emac_init_rxch(struct emac_priv *priv, u32 ch, char *param) /* populate the hardware descriptor */ curr_bd->h_next = emac_virt_to_phys(rxch->active_queue_head, priv); - /* FIXME buff_ptr = dma_map_single(... data_ptr ...) */ - curr_bd->buff_ptr = virt_to_phys(curr_bd->data_ptr); + curr_bd->buff_ptr = dma_map_single(emac_dev, curr_bd->data_ptr, + rxch->buf_size, DMA_FROM_DEVICE); curr_bd->off_b_len = rxch->buf_size; curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT; @@ -1697,6 +1694,12 @@ static void emac_cleanup_rxch(struct emac_priv *priv, u32 ch) curr_bd = rxch->active_queue_head; while (curr_bd) { if (curr_bd->buf_token) { + dma_unmap_single(&priv->ndev->dev, + curr_bd->buff_ptr, + curr_bd->off_b_len + & EMAC_RX_BD_BUF_SIZE, + DMA_FROM_DEVICE); + dev_kfree_skb_any((struct sk_buff *)\ curr_bd->buf_token); } @@ -1871,8 +1874,8 @@ static void emac_addbd_to_rx_queue(struct emac_priv *priv, u32 ch, /* populate the hardware descriptor */ curr_bd->h_next = 0; - /* FIXME buff_ptr = dma_map_single(... buffer ...) */ - curr_bd->buff_ptr = virt_to_phys(buffer); + curr_bd->buff_ptr = dma_map_single(&priv->ndev->dev, buffer, + rxch->buf_size, DMA_FROM_DEVICE); curr_bd->off_b_len = rxch->buf_size; curr_bd->mode = EMAC_CPPI_OWNERSHIP_BIT; curr_bd->next = NULL; @@ -1927,7 +1930,6 @@ static int emac_net_rx_cb(struct emac_priv *priv, p_skb = (struct sk_buff *)net_pkt_list->pkt_token; /* set length of packet */ skb_put(p_skb, net_pkt_list->pkt_length); - EMAC_CACHE_INVALIDATE((unsigned long)p_skb->data, p_skb->len); p_skb->protocol = eth_type_trans(p_skb, priv->ndev); netif_receive_skb(p_skb); priv->net_dev_stats.rx_bytes += net_pkt_list->pkt_length; @@ -1990,6 +1992,11 @@ static int emac_rx_bdproc(struct emac_priv *priv, u32 ch, u32 budget) rx_buf_obj->data_ptr = (char *)curr_bd->data_ptr; rx_buf_obj->length = curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE; rx_buf_obj->buf_token = curr_bd->buf_token; + + dma_unmap_single(&priv->ndev->dev, curr_bd->buff_ptr, + curr_bd->off_b_len & EMAC_RX_BD_BUF_SIZE, + DMA_FROM_DEVICE); + curr_pkt->pkt_token = curr_pkt->buf_list->buf_token; curr_pkt->num_bufs = 1; curr_pkt->pkt_length = @@ -2820,31 +2827,37 @@ static int __devexit davinci_emac_remove(struct platform_device *pdev) return 0; } -static -int davinci_emac_suspend(struct platform_device *pdev, pm_message_t state) +static int davinci_emac_suspend(struct device *dev) { - struct net_device *dev = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); - if (netif_running(dev)) - emac_dev_stop(dev); + if (netif_running(ndev)) + emac_dev_stop(ndev); clk_disable(emac_clk); return 0; } -static int davinci_emac_resume(struct platform_device *pdev) +static int davinci_emac_resume(struct device *dev) { - struct net_device *dev = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + struct net_device *ndev = platform_get_drvdata(pdev); clk_enable(emac_clk); - if (netif_running(dev)) - emac_dev_open(dev); + if (netif_running(ndev)) + emac_dev_open(ndev); return 0; } +static const struct dev_pm_ops davinci_emac_pm_ops = { + .suspend = davinci_emac_suspend, + .resume = davinci_emac_resume, +}; + /** * davinci_emac_driver: EMAC platform driver structure */ @@ -2852,11 +2865,10 @@ static struct platform_driver davinci_emac_driver = { .driver = { .name = "davinci_emac", .owner = THIS_MODULE, + .pm = &davinci_emac_pm_ops, }, .probe = davinci_emac_probe, .remove = __devexit_p(davinci_emac_remove), - .suspend = davinci_emac_suspend, - .resume = davinci_emac_resume, }; /** diff --git a/drivers/net/e100.c b/drivers/net/e100.c index a26ccab057d..b997e578e58 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2858,7 +2858,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, } nic->cbs_pool = pci_pool_create(netdev->name, nic->pdev, - nic->params.cbs.count * sizeof(struct cb), + nic->params.cbs.max * sizeof(struct cb), sizeof(u32), 0); DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %pM\n", diff --git a/drivers/net/igb/e1000_82575.c b/drivers/net/igb/e1000_82575.c index 9d7fa2fb85e..0bc990ec4a8 100644 --- a/drivers/net/igb/e1000_82575.c +++ b/drivers/net/igb/e1000_82575.c @@ -94,6 +94,7 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw) case E1000_DEV_ID_82576_FIBER: case E1000_DEV_ID_82576_SERDES: case E1000_DEV_ID_82576_QUAD_COPPER: + case E1000_DEV_ID_82576_QUAD_COPPER_ET2: case E1000_DEV_ID_82576_SERDES_QUAD: mac->type = e1000_82576; break; diff --git a/drivers/net/igb/e1000_hw.h b/drivers/net/igb/e1000_hw.h index 448005276b2..82a533f5192 100644 --- a/drivers/net/igb/e1000_hw.h +++ b/drivers/net/igb/e1000_hw.h @@ -41,6 +41,7 @@ struct e1000_hw; #define E1000_DEV_ID_82576_FIBER 0x10E6 #define E1000_DEV_ID_82576_SERDES 0x10E7 #define E1000_DEV_ID_82576_QUAD_COPPER 0x10E8 +#define E1000_DEV_ID_82576_QUAD_COPPER_ET2 0x1526 #define E1000_DEV_ID_82576_NS 0x150A #define E1000_DEV_ID_82576_NS_SERDES 0x1518 #define E1000_DEV_ID_82576_SERDES_QUAD 0x150D diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 0ed25f059a0..45a0e4fd587 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -72,6 +72,7 @@ static DEFINE_PCI_DEVICE_TABLE(igb_pci_tbl) = { { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD), board_82575 }, + { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER_ET2), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 }, { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 }, diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 551810fd297..980625feb2c 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -65,7 +65,6 @@ #undef CONFIG_NETWINDER_TX_DMA_PROBLEMS /* Not needed */ #define CONFIG_NETWINDER_RX_DMA_PROBLEMS /* Must have this one! */ #endif -#undef CONFIG_USE_INTERNAL_TIMER /* Just cannot make that timer work */ #define CONFIG_USE_W977_PNP /* Currently needed */ #define PIO_MAX_SPEED 115200 @@ -533,25 +532,6 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb, self->tx_buff.len = skb->len; mtt = irda_get_mtt(skb); -#ifdef CONFIG_USE_INTERNAL_TIMER - if (mtt > 50) { - /* Adjust for timer resolution */ - mtt /= 1000+1; - - /* Setup timer */ - switch_bank(iobase, SET4); - outb(mtt & 0xff, iobase+TMRL); - outb((mtt >> 8) & 0x0f, iobase+TMRH); - - /* Start timer */ - outb(IR_MSL_EN_TMR, iobase+IR_MSL); - self->io.direction = IO_XMIT; - - /* Enable timer interrupt */ - switch_bank(iobase, SET0); - outb(ICR_ETMRI, iobase+ICR); - } else { -#endif IRDA_DEBUG(4, "%s(%ld), mtt=%d\n", __func__ , jiffies, mtt); if (mtt) udelay(mtt); @@ -560,9 +540,6 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb, switch_bank(iobase, SET0); outb(ICR_EDMAI, iobase+ICR); w83977af_dma_write(self, iobase); -#ifdef CONFIG_USE_INTERNAL_TIMER - } -#endif } else { self->tx_buff.data = self->tx_buff.head; self->tx_buff.len = async_wrap_skb(skb, self->tx_buff.data, @@ -876,20 +853,7 @@ static int w83977af_dma_receive_complete(struct w83977af_ir *self) /* Check if we have transferred all data to memory */ switch_bank(iobase, SET0); if (inb(iobase+USR) & USR_RDR) { -#ifdef CONFIG_USE_INTERNAL_TIMER - /* Put this entry back in fifo */ - st_fifo->head--; - st_fifo->len++; - st_fifo->entries[st_fifo->head].status = status; - st_fifo->entries[st_fifo->head].len = len; - - /* Restore set register */ - outb(set, iobase+SSR); - - return FALSE; /* I'll be back! */ -#else udelay(80); /* Should be enough!? */ -#endif } skb = dev_alloc_skb(len+1); diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c index 1f30e163bd9..b405a00817c 100644 --- a/drivers/net/ixgbe/ixgbe_82599.c +++ b/drivers/net/ixgbe/ixgbe_82599.c @@ -39,6 +39,7 @@ #define IXGBE_82599_MC_TBL_SIZE 128 #define IXGBE_82599_VFT_TBL_SIZE 128 +void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw); s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, @@ -68,7 +69,9 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw) if (hw->phy.multispeed_fiber) { /* Set up dual speed SFP+ support */ mac->ops.setup_link = &ixgbe_setup_mac_link_multispeed_fiber; + mac->ops.flap_tx_laser = &ixgbe_flap_tx_laser_multispeed_fiber; } else { + mac->ops.flap_tx_laser = NULL; if ((mac->ops.get_media_type(hw) == ixgbe_media_type_backplane) && (hw->phy.smart_speed == ixgbe_smart_speed_auto || @@ -413,6 +416,41 @@ s32 ixgbe_start_mac_link_82599(struct ixgbe_hw *hw, } /** + * ixgbe_flap_tx_laser_multispeed_fiber - Flap Tx laser + * @hw: pointer to hardware structure + * + * When the driver changes the link speeds that it can support, + * it sets autotry_restart to true to indicate that we need to + * initiate a new autotry session with the link partner. To do + * so, we set the speed then disable and re-enable the tx laser, to + * alert the link partner that it also needs to restart autotry on its + * end. This is consistent with true clause 37 autoneg, which also + * involves a loss of signal. + **/ +void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) +{ + u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); + + hw_dbg(hw, "ixgbe_flap_tx_laser_multispeed_fiber\n"); + + if (hw->mac.autotry_restart) { + /* Disable tx laser; allow 100us to go dark per spec */ + esdp_reg |= IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + IXGBE_WRITE_FLUSH(hw); + udelay(100); + + /* Enable tx laser; allow 100ms to light up */ + esdp_reg &= ~IXGBE_ESDP_SDP3; + IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + IXGBE_WRITE_FLUSH(hw); + msleep(100); + + hw->mac.autotry_restart = false; + } +} + +/** * ixgbe_setup_mac_link_multispeed_fiber - Set MAC link speed * @hw: pointer to hardware structure * @speed: new link speed @@ -440,16 +478,6 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, speed &= phy_link_speed; /* - * When the driver changes the link speeds that it can support, - * it sets autotry_restart to true to indicate that we need to - * initiate a new autotry session with the link partner. To do - * so, we set the speed then disable and re-enable the tx laser, to - * alert the link partner that it also needs to restart autotry on its - * end. This is consistent with true clause 37 autoneg, which also - * involves a loss of signal. - */ - - /* * Try each speed one by one, highest priority first. We do this in * software because 10gb fiber doesn't support speed autonegotiation. */ @@ -466,6 +494,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, /* Set the module link speed */ esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5); IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + IXGBE_WRITE_FLUSH(hw); /* Allow module to change analog characteristics (1G->10G) */ msleep(40); @@ -478,19 +507,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, return status; /* Flap the tx laser if it has not already been done */ - if (hw->mac.autotry_restart) { - /* Disable tx laser; allow 100us to go dark per spec */ - esdp_reg |= IXGBE_ESDP_SDP3; - IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - udelay(100); - - /* Enable tx laser; allow 2ms to light up per spec */ - esdp_reg &= ~IXGBE_ESDP_SDP3; - IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - msleep(2); - - hw->mac.autotry_restart = false; - } + hw->mac.ops.flap_tx_laser(hw); /* * Wait for the controller to acquire link. Per IEEE 802.3ap, @@ -525,6 +542,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, esdp_reg &= ~IXGBE_ESDP_SDP5; esdp_reg |= IXGBE_ESDP_SDP5_DIR; IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); + IXGBE_WRITE_FLUSH(hw); /* Allow module to change analog characteristics (10G->1G) */ msleep(40); @@ -537,19 +555,7 @@ s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw, return status; /* Flap the tx laser if it has not already been done */ - if (hw->mac.autotry_restart) { - /* Disable tx laser; allow 100us to go dark per spec */ - esdp_reg |= IXGBE_ESDP_SDP3; - IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - udelay(100); - - /* Enable tx laser; allow 2ms to light up per spec */ - esdp_reg &= ~IXGBE_ESDP_SDP3; - IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); - msleep(2); - - hw->mac.autotry_restart = false; - } + hw->mac.ops.flap_tx_laser(hw); /* Wait for the link partner to also set speed */ msleep(100); diff --git a/drivers/net/ixgbe/ixgbe_fcoe.c b/drivers/net/ixgbe/ixgbe_fcoe.c index 4123dec0dfb..700cfc0aa1b 100644 --- a/drivers/net/ixgbe/ixgbe_fcoe.c +++ b/drivers/net/ixgbe/ixgbe_fcoe.c @@ -614,9 +614,9 @@ int ixgbe_fcoe_enable(struct net_device *netdev) netdev->vlan_features |= NETIF_F_FSO; netdev->vlan_features |= NETIF_F_FCOE_MTU; netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; - netdev_features_change(netdev); ixgbe_init_interrupt_scheme(adapter); + netdev_features_change(netdev); if (netif_running(netdev)) netdev->netdev_ops->ndo_open(netdev); @@ -660,11 +660,11 @@ int ixgbe_fcoe_disable(struct net_device *netdev) netdev->vlan_features &= ~NETIF_F_FSO; netdev->vlan_features &= ~NETIF_F_FCOE_MTU; netdev->fcoe_ddp_xid = 0; - netdev_features_change(netdev); ixgbe_cleanup_fcoe(adapter); - ixgbe_init_interrupt_scheme(adapter); + netdev_features_change(netdev); + if (netif_running(netdev)) netdev->netdev_ops->ndo_open(netdev); rc = 0; diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 684af371462..d75c46ff31f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -935,10 +935,12 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector, if (skb->prev) skb = ixgbe_transform_rsc_queue(skb, &(rx_ring->rsc_count)); if (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) { - if (IXGBE_RSC_CB(skb)->dma) + if (IXGBE_RSC_CB(skb)->dma) { pci_unmap_single(pdev, IXGBE_RSC_CB(skb)->dma, rx_ring->rx_buf_len, PCI_DMA_FROMDEVICE); + IXGBE_RSC_CB(skb)->dma = 0; + } if (rx_ring->flags & IXGBE_RING_RX_PS_ENABLED) rx_ring->rsc_count += skb_shinfo(skb)->nr_frags; else @@ -3126,10 +3128,12 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter, rx_buffer_info->skb = NULL; do { struct sk_buff *this = skb; - if (IXGBE_RSC_CB(this)->dma) + if (IXGBE_RSC_CB(this)->dma) { pci_unmap_single(pdev, IXGBE_RSC_CB(this)->dma, rx_ring->rx_buf_len, PCI_DMA_FROMDEVICE); + IXGBE_RSC_CB(this)->dma = 0; + } skb = skb->prev; dev_kfree_skb(this); } while (skb); @@ -5018,6 +5022,7 @@ static void ixgbe_multispeed_fiber_task(struct work_struct *work) autoneg = hw->phy.autoneg_advertised; if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); + hw->mac.autotry_restart = false; if (hw->mac.ops.setup_link) hw->mac.ops.setup_link(hw, autoneg, negotiation, true); adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; @@ -6245,9 +6250,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, case IXGBE_DEV_ID_82599_KX4: adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX | IXGBE_WUFC_MC | IXGBE_WUFC_BC); - /* Enable ACPI wakeup in GRC */ - IXGBE_WRITE_REG(hw, IXGBE_GRC, - (IXGBE_READ_REG(hw, IXGBE_GRC) & ~IXGBE_GRC_APME)); break; default: adapter->wol = 0; @@ -6380,6 +6382,16 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) del_timer_sync(&adapter->sfp_timer); cancel_work_sync(&adapter->watchdog_task); cancel_work_sync(&adapter->sfp_task); + if (adapter->hw.phy.multispeed_fiber) { + struct ixgbe_hw *hw = &adapter->hw; + /* + * Restart clause 37 autoneg, disable and re-enable + * the tx laser, to clear & alert the link partner + * that it needs to restart autotry + */ + hw->mac.autotry_restart = true; + hw->mac.ops.flap_tx_laser(hw); + } cancel_work_sync(&adapter->multispeed_fiber_task); cancel_work_sync(&adapter->sfp_config_module_task); if (adapter->flags & IXGBE_FLAG_FDIR_HASH_CAPABLE || diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index 2be90746659..0ed5ab37cc5 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -2397,6 +2397,7 @@ struct ixgbe_mac_operations { s32 (*enable_rx_dma)(struct ixgbe_hw *, u32); /* Link */ + void (*flap_tx_laser)(struct ixgbe_hw *); s32 (*setup_link)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool); s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *, bool); s32 (*get_link_capabilities)(struct ixgbe_hw *, ixgbe_link_speed *, diff --git a/drivers/net/ixgbevf/ethtool.c b/drivers/net/ixgbevf/ethtool.c index 399be0c34c3..6fdd651abcd 100644 --- a/drivers/net/ixgbevf/ethtool.c +++ b/drivers/net/ixgbevf/ethtool.c @@ -46,22 +46,32 @@ struct ixgbe_stats { int sizeof_stat; int stat_offset; int base_stat_offset; + int saved_reset_offset; }; -#define IXGBEVF_STAT(m, b) sizeof(((struct ixgbevf_adapter *)0)->m), \ - offsetof(struct ixgbevf_adapter, m), \ - offsetof(struct ixgbevf_adapter, b) +#define IXGBEVF_STAT(m, b, r) sizeof(((struct ixgbevf_adapter *)0)->m), \ + offsetof(struct ixgbevf_adapter, m), \ + offsetof(struct ixgbevf_adapter, b), \ + offsetof(struct ixgbevf_adapter, r) static struct ixgbe_stats ixgbe_gstrings_stats[] = { - {"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc)}, - {"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc)}, - {"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc)}, - {"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc)}, - {"tx_busy", IXGBEVF_STAT(tx_busy, zero_base)}, - {"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc)}, - {"rx_csum_offload_good", IXGBEVF_STAT(hw_csum_rx_good, zero_base)}, - {"rx_csum_offload_errors", IXGBEVF_STAT(hw_csum_rx_error, zero_base)}, - {"tx_csum_offload_ctxt", IXGBEVF_STAT(hw_csum_tx_good, zero_base)}, - {"rx_header_split", IXGBEVF_STAT(rx_hdr_split, zero_base)}, + {"rx_packets", IXGBEVF_STAT(stats.vfgprc, stats.base_vfgprc, + stats.saved_reset_vfgprc)}, + {"tx_packets", IXGBEVF_STAT(stats.vfgptc, stats.base_vfgptc, + stats.saved_reset_vfgptc)}, + {"rx_bytes", IXGBEVF_STAT(stats.vfgorc, stats.base_vfgorc, + stats.saved_reset_vfgorc)}, + {"tx_bytes", IXGBEVF_STAT(stats.vfgotc, stats.base_vfgotc, + stats.saved_reset_vfgotc)}, + {"tx_busy", IXGBEVF_STAT(tx_busy, zero_base, zero_base)}, + {"multicast", IXGBEVF_STAT(stats.vfmprc, stats.base_vfmprc, + stats.saved_reset_vfmprc)}, + {"rx_csum_offload_good", IXGBEVF_STAT(hw_csum_rx_good, zero_base, + zero_base)}, + {"rx_csum_offload_errors", IXGBEVF_STAT(hw_csum_rx_error, zero_base, + zero_base)}, + {"tx_csum_offload_ctxt", IXGBEVF_STAT(hw_csum_tx_good, zero_base, + zero_base)}, + {"rx_header_split", IXGBEVF_STAT(rx_hdr_split, zero_base, zero_base)}, }; #define IXGBE_QUEUE_STATS_LEN 0 @@ -455,10 +465,14 @@ static void ixgbevf_get_ethtool_stats(struct net_device *netdev, ixgbe_gstrings_stats[i].stat_offset; char *b = (char *)adapter + ixgbe_gstrings_stats[i].base_stat_offset; + char *r = (char *)adapter + + ixgbe_gstrings_stats[i].saved_reset_offset; data[i] = ((ixgbe_gstrings_stats[i].sizeof_stat == sizeof(u64)) ? *(u64 *)p : *(u32 *)p) - ((ixgbe_gstrings_stats[i].sizeof_stat == - sizeof(u64)) ? *(u64 *)b : *(u32 *)b); + sizeof(u64)) ? *(u64 *)b : *(u32 *)b) + + ((ixgbe_gstrings_stats[i].sizeof_stat == + sizeof(u64)) ? *(u64 *)r : *(u32 *)r); } } diff --git a/drivers/net/ixgbevf/ixgbevf_main.c b/drivers/net/ixgbevf/ixgbevf_main.c index ca653c49b76..d6cbd943a6f 100644 --- a/drivers/net/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ixgbevf/ixgbevf_main.c @@ -965,7 +965,7 @@ static irqreturn_t ixgbevf_msix_mbx(int irq, void *data) if ((msg & IXGBE_MBVFICR_VFREQ_MASK) == IXGBE_PF_CONTROL_MSG) mod_timer(&adapter->watchdog_timer, - round_jiffies(jiffies + 10)); + round_jiffies(jiffies + 1)); return IRQ_HANDLED; } @@ -1610,6 +1610,44 @@ static inline void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter, (adapter->rx_ring[rxr].count - 1)); } +static void ixgbevf_save_reset_stats(struct ixgbevf_adapter *adapter) +{ + /* Only save pre-reset stats if there are some */ + if (adapter->stats.vfgprc || adapter->stats.vfgptc) { + adapter->stats.saved_reset_vfgprc += adapter->stats.vfgprc - + adapter->stats.base_vfgprc; + adapter->stats.saved_reset_vfgptc += adapter->stats.vfgptc - + adapter->stats.base_vfgptc; + adapter->stats.saved_reset_vfgorc += adapter->stats.vfgorc - + adapter->stats.base_vfgorc; + adapter->stats.saved_reset_vfgotc += adapter->stats.vfgotc - + adapter->stats.base_vfgotc; + adapter->stats.saved_reset_vfmprc += adapter->stats.vfmprc - + adapter->stats.base_vfmprc; + } +} + +static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + + adapter->stats.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC); + adapter->stats.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB); + adapter->stats.last_vfgorc |= + (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32); + adapter->stats.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC); + adapter->stats.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB); + adapter->stats.last_vfgotc |= + (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGOTC_MSB))) << 32); + adapter->stats.last_vfmprc = IXGBE_READ_REG(hw, IXGBE_VFMPRC); + + adapter->stats.base_vfgprc = adapter->stats.last_vfgprc; + adapter->stats.base_vfgorc = adapter->stats.last_vfgorc; + adapter->stats.base_vfgptc = adapter->stats.last_vfgptc; + adapter->stats.base_vfgotc = adapter->stats.last_vfgotc; + adapter->stats.base_vfmprc = adapter->stats.last_vfmprc; +} + static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter) { struct net_device *netdev = adapter->netdev; @@ -1656,6 +1694,9 @@ static int ixgbevf_up_complete(struct ixgbevf_adapter *adapter) /* enable transmits */ netif_tx_start_all_queues(netdev); + ixgbevf_save_reset_stats(adapter); + ixgbevf_init_last_counter_stats(adapter); + /* bring the link up in the watchdog, this could race with our first * link up interrupt but shouldn't be a problem */ adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; @@ -2228,27 +2269,6 @@ out: return err; } -static void ixgbevf_init_last_counter_stats(struct ixgbevf_adapter *adapter) -{ - struct ixgbe_hw *hw = &adapter->hw; - - adapter->stats.last_vfgprc = IXGBE_READ_REG(hw, IXGBE_VFGPRC); - adapter->stats.last_vfgorc = IXGBE_READ_REG(hw, IXGBE_VFGORC_LSB); - adapter->stats.last_vfgorc |= - (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGORC_MSB))) << 32); - adapter->stats.last_vfgptc = IXGBE_READ_REG(hw, IXGBE_VFGPTC); - adapter->stats.last_vfgotc = IXGBE_READ_REG(hw, IXGBE_VFGOTC_LSB); - adapter->stats.last_vfgotc |= - (((u64)(IXGBE_READ_REG(hw, IXGBE_VFGOTC_MSB))) << 32); - adapter->stats.last_vfmprc = IXGBE_READ_REG(hw, IXGBE_VFMPRC); - - adapter->stats.base_vfgprc = adapter->stats.last_vfgprc; - adapter->stats.base_vfgorc = adapter->stats.last_vfgorc; - adapter->stats.base_vfgptc = adapter->stats.last_vfgptc; - adapter->stats.base_vfgotc = adapter->stats.last_vfgotc; - adapter->stats.base_vfmprc = adapter->stats.last_vfmprc; -} - #define UPDATE_VF_COUNTER_32bit(reg, last_counter, counter) \ { \ u32 current_counter = IXGBE_READ_REG(hw, reg); \ @@ -2399,7 +2419,7 @@ static void ixgbevf_watchdog_task(struct work_struct *work) if (!netif_carrier_ok(netdev)) { hw_dbg(&adapter->hw, "NIC Link is Up %s, ", ((link_speed == IXGBE_LINK_SPEED_10GB_FULL) ? - "10 Gbps" : "1 Gbps")); + "10 Gbps\n" : "1 Gbps\n")); netif_carrier_on(netdev); netif_tx_wake_all_queues(netdev); } else { @@ -2416,9 +2436,9 @@ static void ixgbevf_watchdog_task(struct work_struct *work) } } -pf_has_reset: ixgbevf_update_stats(adapter); +pf_has_reset: /* Force detection of hung controller every watchdog period */ adapter->detect_tx_hung = true; @@ -2675,7 +2695,7 @@ static int ixgbevf_open(struct net_device *netdev) if (hw->adapter_stopped) { err = IXGBE_ERR_MBX; printk(KERN_ERR "Unable to start - perhaps the PF" - "Driver isn't up yet\n"); + " Driver isn't up yet\n"); goto err_setup_reset; } } @@ -3390,8 +3410,6 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, /* setup the private structure */ err = ixgbevf_sw_init(adapter); - ixgbevf_init_last_counter_stats(adapter); - #ifdef MAX_SKB_FRAGS netdev->features = NETIF_F_SG | NETIF_F_IP_CSUM | @@ -3449,6 +3467,8 @@ static int __devinit ixgbevf_probe(struct pci_dev *pdev, adapter->netdev_registered = true; + ixgbevf_init_last_counter_stats(adapter); + /* print the MAC address */ hw_dbg(hw, "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n", netdev->dev_addr[0], diff --git a/drivers/net/ixgbevf/vf.h b/drivers/net/ixgbevf/vf.h index 799600e9270..1f31b052d4b 100644 --- a/drivers/net/ixgbevf/vf.h +++ b/drivers/net/ixgbevf/vf.h @@ -157,6 +157,12 @@ struct ixgbevf_hw_stats { u64 vfgorc; u64 vfgotc; u64 vfmprc; + + u64 saved_reset_vfgprc; + u64 saved_reset_vfgptc; + u64 saved_reset_vfgorc; + u64 saved_reset_vfgotc; + u64 saved_reset_vfmprc; }; struct ixgbevf_info { diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 0f31497833d..c0b59a55538 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -946,6 +946,8 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx) jme->jme_vlan_rx(skb, jme->vlgrp, le16_to_cpu(rxdesc->descwb.vlan)); NET_STAT(jme).rx_bytes += 4; + } else { + dev_kfree_skb(skb); } } else { jme->jme_rx(skb); @@ -2081,12 +2083,45 @@ jme_tx_timeout(struct net_device *netdev) jme_reset_link(jme); } +static inline void jme_pause_rx(struct jme_adapter *jme) +{ + atomic_dec(&jme->link_changing); + + jme_set_rx_pcc(jme, PCC_OFF); + if (test_bit(JME_FLAG_POLL, &jme->flags)) { + JME_NAPI_DISABLE(jme); + } else { + tasklet_disable(&jme->rxclean_task); + tasklet_disable(&jme->rxempty_task); + } +} + +static inline void jme_resume_rx(struct jme_adapter *jme) +{ + struct dynpcc_info *dpi = &(jme->dpi); + + if (test_bit(JME_FLAG_POLL, &jme->flags)) { + JME_NAPI_ENABLE(jme); + } else { + tasklet_hi_enable(&jme->rxclean_task); + tasklet_hi_enable(&jme->rxempty_task); + } + dpi->cur = PCC_P1; + dpi->attempt = PCC_P1; + dpi->cnt = 0; + jme_set_rx_pcc(jme, PCC_P1); + + atomic_inc(&jme->link_changing); +} + static void jme_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp) { struct jme_adapter *jme = netdev_priv(netdev); + jme_pause_rx(jme); jme->vlgrp = grp; + jme_resume_rx(jme); } static void diff --git a/drivers/net/jme.h b/drivers/net/jme.h index c19db9146a2..07ad3a45718 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -25,7 +25,7 @@ #define __JME_H_INCLUDED__ #define DRV_NAME "jme" -#define DRV_VERSION "1.0.5" +#define DRV_VERSION "1.0.6" #define PFX DRV_NAME ": " #define PCI_DEVICE_ID_JMICRON_JMC250 0x0250 diff --git a/drivers/net/ks8851.c b/drivers/net/ks8851.c index 0573e0bb444..13cc1ca261d 100644 --- a/drivers/net/ks8851.c +++ b/drivers/net/ks8851.c @@ -976,7 +976,6 @@ static void ks8851_set_rx_mode(struct net_device *dev) crc >>= (32 - 6); /* get top six bits */ rxctrl.mchash[crc >> 4] |= (1 << (crc & 0xf)); - mcptr = mcptr->next; } rxctrl.rxcr1 = RXCR1_RXME | RXCR1_RXPAFMA; diff --git a/drivers/net/ksz884x.c b/drivers/net/ksz884x.c index 7264a3e5c2c..0f59099ee72 100644 --- a/drivers/net/ksz884x.c +++ b/drivers/net/ksz884x.c @@ -4899,8 +4899,10 @@ static int netdev_tx(struct sk_buff *skb, struct net_device *dev) struct sk_buff *org_skb = skb; skb = dev_alloc_skb(org_skb->len); - if (!skb) - return NETDEV_TX_BUSY; + if (!skb) { + rc = NETDEV_TX_BUSY; + goto unlock; + } skb_copy_and_csum_dev(org_skb, skb->data); org_skb->ip_summed = 0; skb->len = org_skb->len; @@ -4914,7 +4916,7 @@ static int netdev_tx(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); rc = NETDEV_TX_BUSY; } - +unlock: spin_unlock_irq(&hw_priv->hwlock); return rc; diff --git a/drivers/net/mlx4/main.c b/drivers/net/mlx4/main.c index 8f6e816a739..b402a95c87c 100644 --- a/drivers/net/mlx4/main.c +++ b/drivers/net/mlx4/main.c @@ -1023,6 +1023,7 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port) info->port_attr.attr.mode = S_IRUGO | S_IWUSR; info->port_attr.show = show_port_type; info->port_attr.store = set_port_type; + sysfs_attr_init(&info->port_attr.attr); err = device_create_file(&dev->pdev->dev, &info->port_attr); if (err) { diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 676c513e12f..e84dd3ee9c5 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -3687,7 +3687,6 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp) if (status != 0) { dev_err(&mgp->pdev->dev, "failed reset\n"); goto abort_with_fw; - return; } mgp->max_intr_slots = cmd.data0 / sizeof(struct mcp_slot); diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 992dbfffdb0..f4347f88b6f 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -142,7 +142,7 @@ bad_clone_list[] __initdata = { {"PCM-4823", "PCM-4823", {0x00, 0xc0, 0x6c}}, /* Broken Advantech MoBo */ {"REALTEK", "RTL8019", {0x00, 0x00, 0xe8}}, /* no-name with Realtek chip */ #ifdef CONFIG_MACH_TX49XX - {"RBHMA4X00-RTL8019", "RBHMA4X00/RTL8019", {0x00, 0x60, 0x0a}}, /* Toshiba built-in */ + {"RBHMA4X00-RTL8019", "RBHMA4X00-RTL8019", {0x00, 0x60, 0x0a}}, /* Toshiba built-in */ #endif {"LCS-8834", "LCS-8836", {0x04, 0x04, 0x37}}, /* ShinyNet (SET) */ {NULL,} diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 9fbb2eba9a0..449a9825200 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -756,6 +756,7 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) /* Try to dequeue as many skbs from reorder_q as we can. */ pppol2tp_recv_dequeue(session); + sock_put(sock); return 0; @@ -772,6 +773,7 @@ discard_bad_csum: UDP_INC_STATS_USER(&init_net, UDP_MIB_INERRORS, 0); tunnel->stats.rx_errors++; kfree_skb(skb); + sock_put(sock); return 0; @@ -1180,7 +1182,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) /* Calculate UDP checksum if configured to do so */ if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) skb->ip_summed = CHECKSUM_NONE; - else if (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM)) { + else if ((skb_dst(skb) && skb_dst(skb)->dev) && + (!(skb_dst(skb)->dev->features & NETIF_F_V4_CSUM))) { skb->ip_summed = CHECKSUM_COMPLETE; csum = skb_checksum(skb, 0, udp_len, 0); uh->check = csum_tcpudp_magic(inet->inet_saddr, @@ -1661,6 +1664,7 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr, if (tunnel_sock == NULL) goto end; + sock_hold(tunnel_sock); tunnel = tunnel_sock->sk_user_data; } else { tunnel = pppol2tp_tunnel_find(sock_net(sk), sp->pppol2tp.s_tunnel); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index df70657260d..2eb7f8a0d92 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -5819,10 +5819,8 @@ static void s2io_vpd_read(struct s2io_nic *nic) } } - if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) { - memset(nic->product_name, 0, vpd_data[1]); + if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) memcpy(nic->product_name, &vpd_data[3], vpd_data[1]); - } kfree(vpd_data); swstats->mem_freed += 256; } diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 32d93564a74..ba56ce4382d 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -204,6 +204,14 @@ config USB_NET_DM9601 This option adds support for Davicom DM9601 based USB 1.1 10/100 Ethernet adapters. +config USB_NET_SMSC75XX + tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices" + depends on USB_USBNET + select CRC32 + help + This option adds support for SMSC LAN95XX based USB 2.0 + Gigabit Ethernet adapters. + config USB_NET_SMSC95XX tristate "SMSC LAN95XX based USB 2.0 10/100 ethernet devices" depends on USB_USBNET diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index e17afb78f37..82ea62955b5 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_USB_NET_AX8817X) += asix.o obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o obj-$(CONFIG_USB_NET_DM9601) += dm9601.o +obj-$(CONFIG_USB_NET_SMSC75XX) += smsc75xx.o obj-$(CONFIG_USB_NET_SMSC95XX) += smsc95xx.o obj-$(CONFIG_USB_NET_GL620A) += gl620a.o obj-$(CONFIG_USB_NET_NET1080) += net1080.o diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 6895f153123..be0cc99e881 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1155,9 +1155,6 @@ static void _hso_serial_set_termios(struct tty_struct *tty, static void hso_resubmit_rx_bulk_urb(struct hso_serial *serial, struct urb *urb) { int result; -#ifdef CONFIG_HSO_AUTOPM - usb_mark_last_busy(urb->dev); -#endif /* We are done with this URB, resubmit it. Prep the USB to wait for * another frame */ usb_fill_bulk_urb(urb, serial->parent->usb, diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c new file mode 100644 index 00000000000..300e3e764fa --- /dev/null +++ b/drivers/net/usb/smsc75xx.c @@ -0,0 +1,1288 @@ + /*************************************************************************** + * + * Copyright (C) 2007-2010 SMSC + * + * 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. + * + *****************************************************************************/ + +#include <linux/module.h> +#include <linux/kmod.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/usb.h> +#include <linux/crc32.h> +#include <linux/usb/usbnet.h> +#include "smsc75xx.h" + +#define SMSC_CHIPNAME "smsc75xx" +#define SMSC_DRIVER_VERSION "1.0.0" +#define HS_USB_PKT_SIZE (512) +#define FS_USB_PKT_SIZE (64) +#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE) +#define DEFAULT_FS_BURST_CAP_SIZE (6 * 1024 + 33 * FS_USB_PKT_SIZE) +#define DEFAULT_BULK_IN_DELAY (0x00002000) +#define MAX_SINGLE_PACKET_SIZE (9000) +#define LAN75XX_EEPROM_MAGIC (0x7500) +#define EEPROM_MAC_OFFSET (0x01) +#define DEFAULT_TX_CSUM_ENABLE (true) +#define DEFAULT_RX_CSUM_ENABLE (true) +#define DEFAULT_TSO_ENABLE (true) +#define SMSC75XX_INTERNAL_PHY_ID (1) +#define SMSC75XX_TX_OVERHEAD (8) +#define MAX_RX_FIFO_SIZE (20 * 1024) +#define MAX_TX_FIFO_SIZE (12 * 1024) +#define USB_VENDOR_ID_SMSC (0x0424) +#define USB_PRODUCT_ID_LAN7500 (0x7500) +#define USB_PRODUCT_ID_LAN7505 (0x7505) + +#define check_warn(ret, fmt, args...) \ + ({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); }) + +#define check_warn_return(ret, fmt, args...) \ + ({ if (ret < 0) { netdev_warn(dev->net, fmt, ##args); return ret; } }) + +#define check_warn_goto_done(ret, fmt, args...) \ + ({ if (ret < 0) { netdev_warn(dev->net, fmt, ##args); goto done; } }) + +struct smsc75xx_priv { + struct usbnet *dev; + u32 rfe_ctl; + u32 multicast_hash_table[DP_SEL_VHF_HASH_LEN]; + bool use_rx_csum; + struct mutex dataport_mutex; + spinlock_t rfe_ctl_lock; + struct work_struct set_multicast; +}; + +struct usb_context { + struct usb_ctrlrequest req; + struct usbnet *dev; +}; + +static int turbo_mode = true; +module_param(turbo_mode, bool, 0644); +MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); + +static int __must_check smsc75xx_read_reg(struct usbnet *dev, u32 index, + u32 *data) +{ + u32 *buf = kmalloc(4, GFP_KERNEL); + int ret; + + BUG_ON(!dev); + + if (!buf) + return -ENOMEM; + + ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), + USB_VENDOR_REQUEST_READ_REGISTER, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 00, index, buf, 4, USB_CTRL_GET_TIMEOUT); + + if (unlikely(ret < 0)) + netdev_warn(dev->net, + "Failed to read register index 0x%08x", index); + + le32_to_cpus(buf); + *data = *buf; + kfree(buf); + + return ret; +} + +static int __must_check smsc75xx_write_reg(struct usbnet *dev, u32 index, + u32 data) +{ + u32 *buf = kmalloc(4, GFP_KERNEL); + int ret; + + BUG_ON(!dev); + + if (!buf) + return -ENOMEM; + + *buf = data; + cpu_to_le32s(buf); + + ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), + USB_VENDOR_REQUEST_WRITE_REGISTER, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 00, index, buf, 4, USB_CTRL_SET_TIMEOUT); + + if (unlikely(ret < 0)) + netdev_warn(dev->net, + "Failed to write register index 0x%08x", index); + + kfree(buf); + + return ret; +} + +/* Loop until the read is completed with timeout + * called with phy_mutex held */ +static int smsc75xx_phy_wait_not_busy(struct usbnet *dev) +{ + unsigned long start_time = jiffies; + u32 val; + int ret; + + do { + ret = smsc75xx_read_reg(dev, MII_ACCESS, &val); + check_warn_return(ret, "Error reading MII_ACCESS"); + + if (!(val & MII_ACCESS_BUSY)) + return 0; + } while (!time_after(jiffies, start_time + HZ)); + + return -EIO; +} + +static int smsc75xx_mdio_read(struct net_device *netdev, int phy_id, int idx) +{ + struct usbnet *dev = netdev_priv(netdev); + u32 val, addr; + int ret; + + mutex_lock(&dev->phy_mutex); + + /* confirm MII not busy */ + ret = smsc75xx_phy_wait_not_busy(dev); + check_warn_goto_done(ret, "MII is busy in smsc75xx_mdio_read"); + + /* set the address, index & direction (read from PHY) */ + phy_id &= dev->mii.phy_id_mask; + idx &= dev->mii.reg_num_mask; + addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR) + | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR) + | MII_ACCESS_READ; + ret = smsc75xx_write_reg(dev, MII_ACCESS, addr); + check_warn_goto_done(ret, "Error writing MII_ACCESS"); + + ret = smsc75xx_phy_wait_not_busy(dev); + check_warn_goto_done(ret, "Timed out reading MII reg %02X", idx); + + ret = smsc75xx_read_reg(dev, MII_DATA, &val); + check_warn_goto_done(ret, "Error reading MII_DATA"); + + ret = (u16)(val & 0xFFFF); + +done: + mutex_unlock(&dev->phy_mutex); + return ret; +} + +static void smsc75xx_mdio_write(struct net_device *netdev, int phy_id, int idx, + int regval) +{ + struct usbnet *dev = netdev_priv(netdev); + u32 val, addr; + int ret; + + mutex_lock(&dev->phy_mutex); + + /* confirm MII not busy */ + ret = smsc75xx_phy_wait_not_busy(dev); + check_warn_goto_done(ret, "MII is busy in smsc75xx_mdio_write"); + + val = regval; + ret = smsc75xx_write_reg(dev, MII_DATA, val); + check_warn_goto_done(ret, "Error writing MII_DATA"); + + /* set the address, index & direction (write to PHY) */ + phy_id &= dev->mii.phy_id_mask; + idx &= dev->mii.reg_num_mask; + addr = ((phy_id << MII_ACCESS_PHY_ADDR_SHIFT) & MII_ACCESS_PHY_ADDR) + | ((idx << MII_ACCESS_REG_ADDR_SHIFT) & MII_ACCESS_REG_ADDR) + | MII_ACCESS_WRITE; + ret = smsc75xx_write_reg(dev, MII_ACCESS, addr); + check_warn_goto_done(ret, "Error writing MII_ACCESS"); + + ret = smsc75xx_phy_wait_not_busy(dev); + check_warn_goto_done(ret, "Timed out writing MII reg %02X", idx); + +done: + mutex_unlock(&dev->phy_mutex); +} + +static int smsc75xx_wait_eeprom(struct usbnet *dev) +{ + unsigned long start_time = jiffies; + u32 val; + int ret; + + do { + ret = smsc75xx_read_reg(dev, E2P_CMD, &val); + check_warn_return(ret, "Error reading E2P_CMD"); + + if (!(val & E2P_CMD_BUSY) || (val & E2P_CMD_TIMEOUT)) + break; + udelay(40); + } while (!time_after(jiffies, start_time + HZ)); + + if (val & (E2P_CMD_TIMEOUT | E2P_CMD_BUSY)) { + netdev_warn(dev->net, "EEPROM read operation timeout"); + return -EIO; + } + + return 0; +} + +static int smsc75xx_eeprom_confirm_not_busy(struct usbnet *dev) +{ + unsigned long start_time = jiffies; + u32 val; + int ret; + + do { + ret = smsc75xx_read_reg(dev, E2P_CMD, &val); + check_warn_return(ret, "Error reading E2P_CMD"); + + if (!(val & E2P_CMD_BUSY)) + return 0; + + udelay(40); + } while (!time_after(jiffies, start_time + HZ)); + + netdev_warn(dev->net, "EEPROM is busy"); + return -EIO; +} + +static int smsc75xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length, + u8 *data) +{ + u32 val; + int i, ret; + + BUG_ON(!dev); + BUG_ON(!data); + + ret = smsc75xx_eeprom_confirm_not_busy(dev); + if (ret) + return ret; + + for (i = 0; i < length; i++) { + val = E2P_CMD_BUSY | E2P_CMD_READ | (offset & E2P_CMD_ADDR); + ret = smsc75xx_write_reg(dev, E2P_CMD, val); + check_warn_return(ret, "Error writing E2P_CMD"); + + ret = smsc75xx_wait_eeprom(dev); + if (ret < 0) + return ret; + + ret = smsc75xx_read_reg(dev, E2P_DATA, &val); + check_warn_return(ret, "Error reading E2P_DATA"); + + data[i] = val & 0xFF; + offset++; + } + + return 0; +} + +static int smsc75xx_write_eeprom(struct usbnet *dev, u32 offset, u32 length, + u8 *data) +{ + u32 val; + int i, ret; + + BUG_ON(!dev); + BUG_ON(!data); + + ret = smsc75xx_eeprom_confirm_not_busy(dev); + if (ret) + return ret; + + /* Issue write/erase enable command */ + val = E2P_CMD_BUSY | E2P_CMD_EWEN; + ret = smsc75xx_write_reg(dev, E2P_CMD, val); + check_warn_return(ret, "Error writing E2P_CMD"); + + ret = smsc75xx_wait_eeprom(dev); + if (ret < 0) + return ret; + + for (i = 0; i < length; i++) { + + /* Fill data register */ + val = data[i]; + ret = smsc75xx_write_reg(dev, E2P_DATA, val); + check_warn_return(ret, "Error writing E2P_DATA"); + + /* Send "write" command */ + val = E2P_CMD_BUSY | E2P_CMD_WRITE | (offset & E2P_CMD_ADDR); + ret = smsc75xx_write_reg(dev, E2P_CMD, val); + check_warn_return(ret, "Error writing E2P_CMD"); + + ret = smsc75xx_wait_eeprom(dev); + if (ret < 0) + return ret; + + offset++; + } + + return 0; +} + +static int smsc75xx_dataport_wait_not_busy(struct usbnet *dev) +{ + int i, ret; + + for (i = 0; i < 100; i++) { + u32 dp_sel; + ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel); + check_warn_return(ret, "Error reading DP_SEL"); + + if (dp_sel & DP_SEL_DPRDY) + return 0; + + udelay(40); + } + + netdev_warn(dev->net, "smsc75xx_dataport_wait_not_busy timed out"); + + return -EIO; +} + +static int smsc75xx_dataport_write(struct usbnet *dev, u32 ram_select, u32 addr, + u32 length, u32 *buf) +{ + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + u32 dp_sel; + int i, ret; + + mutex_lock(&pdata->dataport_mutex); + + ret = smsc75xx_dataport_wait_not_busy(dev); + check_warn_goto_done(ret, "smsc75xx_dataport_write busy on entry"); + + ret = smsc75xx_read_reg(dev, DP_SEL, &dp_sel); + check_warn_goto_done(ret, "Error reading DP_SEL"); + + dp_sel &= ~DP_SEL_RSEL; + dp_sel |= ram_select; + ret = smsc75xx_write_reg(dev, DP_SEL, dp_sel); + check_warn_goto_done(ret, "Error writing DP_SEL"); + + for (i = 0; i < length; i++) { + ret = smsc75xx_write_reg(dev, DP_ADDR, addr + i); + check_warn_goto_done(ret, "Error writing DP_ADDR"); + + ret = smsc75xx_write_reg(dev, DP_DATA, buf[i]); + check_warn_goto_done(ret, "Error writing DP_DATA"); + + ret = smsc75xx_write_reg(dev, DP_CMD, DP_CMD_WRITE); + check_warn_goto_done(ret, "Error writing DP_CMD"); + + ret = smsc75xx_dataport_wait_not_busy(dev); + check_warn_goto_done(ret, "smsc75xx_dataport_write timeout"); + } + +done: + mutex_unlock(&pdata->dataport_mutex); + return ret; +} + +/* returns hash bit number for given MAC address */ +static u32 smsc75xx_hash(char addr[ETH_ALEN]) +{ + return (ether_crc(ETH_ALEN, addr) >> 23) & 0x1ff; +} + +static void smsc75xx_deferred_multicast_write(struct work_struct *param) +{ + struct smsc75xx_priv *pdata = + container_of(param, struct smsc75xx_priv, set_multicast); + struct usbnet *dev = pdata->dev; + int ret; + + netif_dbg(dev, drv, dev->net, "deferred multicast write 0x%08x", + pdata->rfe_ctl); + + smsc75xx_dataport_write(dev, DP_SEL_VHF, DP_SEL_VHF_VLAN_LEN, + DP_SEL_VHF_HASH_LEN, pdata->multicast_hash_table); + + ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); + check_warn(ret, "Error writing RFE_CRL"); +} + +static void smsc75xx_set_multicast(struct net_device *netdev) +{ + struct usbnet *dev = netdev_priv(netdev); + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + unsigned long flags; + int i; + + spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); + + pdata->rfe_ctl &= + ~(RFE_CTL_AU | RFE_CTL_AM | RFE_CTL_DPF | RFE_CTL_MHF); + pdata->rfe_ctl |= RFE_CTL_AB; + + for (i = 0; i < DP_SEL_VHF_HASH_LEN; i++) + pdata->multicast_hash_table[i] = 0; + + if (dev->net->flags & IFF_PROMISC) { + netif_dbg(dev, drv, dev->net, "promiscuous mode enabled"); + pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_AU; + } else if (dev->net->flags & IFF_ALLMULTI) { + netif_dbg(dev, drv, dev->net, "receive all multicast enabled"); + pdata->rfe_ctl |= RFE_CTL_AM | RFE_CTL_DPF; + } else if (!netdev_mc_empty(dev->net)) { + struct dev_mc_list *mc_list; + + netif_dbg(dev, drv, dev->net, "receive multicast hash filter"); + + pdata->rfe_ctl |= RFE_CTL_MHF | RFE_CTL_DPF; + + netdev_for_each_mc_addr(mc_list, netdev) { + u32 bitnum = smsc75xx_hash(mc_list->dmi_addr); + pdata->multicast_hash_table[bitnum / 32] |= + (1 << (bitnum % 32)); + } + } else { + netif_dbg(dev, drv, dev->net, "receive own packets only"); + pdata->rfe_ctl |= RFE_CTL_DPF; + } + + spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); + + /* defer register writes to a sleepable context */ + schedule_work(&pdata->set_multicast); +} + +static int smsc75xx_update_flowcontrol(struct usbnet *dev, u8 duplex, + u16 lcladv, u16 rmtadv) +{ + u32 flow = 0, fct_flow = 0; + int ret; + + if (duplex == DUPLEX_FULL) { + u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); + + if (cap & FLOW_CTRL_TX) { + flow = (FLOW_TX_FCEN | 0xFFFF); + /* set fct_flow thresholds to 20% and 80% */ + fct_flow = (8 << 8) | 32; + } + + if (cap & FLOW_CTRL_RX) + flow |= FLOW_RX_FCEN; + + netif_dbg(dev, link, dev->net, "rx pause %s, tx pause %s", + (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), + (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); + } else { + netif_dbg(dev, link, dev->net, "half duplex"); + } + + ret = smsc75xx_write_reg(dev, FLOW, flow); + check_warn_return(ret, "Error writing FLOW"); + + ret = smsc75xx_write_reg(dev, FCT_FLOW, fct_flow); + check_warn_return(ret, "Error writing FCT_FLOW"); + + return 0; +} + +static int smsc75xx_link_reset(struct usbnet *dev) +{ + struct mii_if_info *mii = &dev->mii; + struct ethtool_cmd ecmd; + u16 lcladv, rmtadv; + int ret; + + /* clear interrupt status */ + ret = smsc75xx_mdio_read(dev->net, mii->phy_id, PHY_INT_SRC); + check_warn_return(ret, "Error reading PHY_INT_SRC"); + + ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL); + check_warn_return(ret, "Error writing INT_STS"); + + mii_check_media(mii, 1, 1); + mii_ethtool_gset(&dev->mii, &ecmd); + lcladv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); + rmtadv = smsc75xx_mdio_read(dev->net, mii->phy_id, MII_LPA); + + netif_dbg(dev, link, dev->net, "speed: %d duplex: %d lcladv: %04x" + " rmtadv: %04x", ecmd.speed, ecmd.duplex, lcladv, rmtadv); + + return smsc75xx_update_flowcontrol(dev, ecmd.duplex, lcladv, rmtadv); +} + +static void smsc75xx_status(struct usbnet *dev, struct urb *urb) +{ + u32 intdata; + + if (urb->actual_length != 4) { + netdev_warn(dev->net, + "unexpected urb length %d", urb->actual_length); + return; + } + + memcpy(&intdata, urb->transfer_buffer, 4); + le32_to_cpus(&intdata); + + netif_dbg(dev, link, dev->net, "intdata: 0x%08X", intdata); + + if (intdata & INT_ENP_PHY_INT) + usbnet_defer_kevent(dev, EVENT_LINK_RESET); + else + netdev_warn(dev->net, + "unexpected interrupt, intdata=0x%08X", intdata); +} + +/* Enable or disable Rx checksum offload engine */ +static int smsc75xx_set_rx_csum_offload(struct usbnet *dev) +{ + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + unsigned long flags; + int ret; + + spin_lock_irqsave(&pdata->rfe_ctl_lock, flags); + + if (pdata->use_rx_csum) + pdata->rfe_ctl |= RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM; + else + pdata->rfe_ctl &= ~(RFE_CTL_TCPUDP_CKM | RFE_CTL_IP_CKM); + + spin_unlock_irqrestore(&pdata->rfe_ctl_lock, flags); + + ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); + check_warn_return(ret, "Error writing RFE_CTL"); + + return 0; +} + +static int smsc75xx_ethtool_get_eeprom_len(struct net_device *net) +{ + return MAX_EEPROM_SIZE; +} + +static int smsc75xx_ethtool_get_eeprom(struct net_device *netdev, + struct ethtool_eeprom *ee, u8 *data) +{ + struct usbnet *dev = netdev_priv(netdev); + + ee->magic = LAN75XX_EEPROM_MAGIC; + + return smsc75xx_read_eeprom(dev, ee->offset, ee->len, data); +} + +static int smsc75xx_ethtool_set_eeprom(struct net_device *netdev, + struct ethtool_eeprom *ee, u8 *data) +{ + struct usbnet *dev = netdev_priv(netdev); + + if (ee->magic != LAN75XX_EEPROM_MAGIC) { + netdev_warn(dev->net, + "EEPROM: magic value mismatch: 0x%x", ee->magic); + return -EINVAL; + } + + return smsc75xx_write_eeprom(dev, ee->offset, ee->len, data); +} + +static u32 smsc75xx_ethtool_get_rx_csum(struct net_device *netdev) +{ + struct usbnet *dev = netdev_priv(netdev); + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + + return pdata->use_rx_csum; +} + +static int smsc75xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) +{ + struct usbnet *dev = netdev_priv(netdev); + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + + pdata->use_rx_csum = !!val; + + return smsc75xx_set_rx_csum_offload(dev); +} + +static int smsc75xx_ethtool_set_tso(struct net_device *netdev, u32 data) +{ + if (data) + netdev->features |= NETIF_F_TSO | NETIF_F_TSO6; + else + netdev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + + return 0; +} + +static const struct ethtool_ops smsc75xx_ethtool_ops = { + .get_link = usbnet_get_link, + .nway_reset = usbnet_nway_reset, + .get_drvinfo = usbnet_get_drvinfo, + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .get_eeprom_len = smsc75xx_ethtool_get_eeprom_len, + .get_eeprom = smsc75xx_ethtool_get_eeprom, + .set_eeprom = smsc75xx_ethtool_set_eeprom, + .get_tx_csum = ethtool_op_get_tx_csum, + .set_tx_csum = ethtool_op_set_tx_hw_csum, + .get_rx_csum = smsc75xx_ethtool_get_rx_csum, + .set_rx_csum = smsc75xx_ethtool_set_rx_csum, + .get_tso = ethtool_op_get_tso, + .set_tso = smsc75xx_ethtool_set_tso, +}; + +static int smsc75xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) +{ + struct usbnet *dev = netdev_priv(netdev); + + if (!netif_running(netdev)) + return -EINVAL; + + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); +} + +static void smsc75xx_init_mac_address(struct usbnet *dev) +{ + /* try reading mac address from EEPROM */ + if (smsc75xx_read_eeprom(dev, EEPROM_MAC_OFFSET, ETH_ALEN, + dev->net->dev_addr) == 0) { + if (is_valid_ether_addr(dev->net->dev_addr)) { + /* eeprom values are valid so use them */ + netif_dbg(dev, ifup, dev->net, + "MAC address read from EEPROM"); + return; + } + } + + /* no eeprom, or eeprom values are invalid. generate random MAC */ + random_ether_addr(dev->net->dev_addr); + netif_dbg(dev, ifup, dev->net, "MAC address set to random_ether_addr"); +} + +static int smsc75xx_set_mac_address(struct usbnet *dev) +{ + u32 addr_lo = dev->net->dev_addr[0] | dev->net->dev_addr[1] << 8 | + dev->net->dev_addr[2] << 16 | dev->net->dev_addr[3] << 24; + u32 addr_hi = dev->net->dev_addr[4] | dev->net->dev_addr[5] << 8; + + int ret = smsc75xx_write_reg(dev, RX_ADDRH, addr_hi); + check_warn_return(ret, "Failed to write RX_ADDRH: %d", ret); + + ret = smsc75xx_write_reg(dev, RX_ADDRL, addr_lo); + check_warn_return(ret, "Failed to write RX_ADDRL: %d", ret); + + addr_hi |= ADDR_FILTX_FB_VALID; + ret = smsc75xx_write_reg(dev, ADDR_FILTX, addr_hi); + check_warn_return(ret, "Failed to write ADDR_FILTX: %d", ret); + + ret = smsc75xx_write_reg(dev, ADDR_FILTX + 4, addr_lo); + check_warn_return(ret, "Failed to write ADDR_FILTX+4: %d", ret); + + return 0; +} + +static int smsc75xx_phy_initialize(struct usbnet *dev) +{ + int bmcr, timeout = 0; + + /* Initialize MII structure */ + dev->mii.dev = dev->net; + dev->mii.mdio_read = smsc75xx_mdio_read; + dev->mii.mdio_write = smsc75xx_mdio_write; + dev->mii.phy_id_mask = 0x1f; + dev->mii.reg_num_mask = 0x1f; + dev->mii.phy_id = SMSC75XX_INTERNAL_PHY_ID; + + /* reset phy and wait for reset to complete */ + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + + do { + msleep(10); + bmcr = smsc75xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); + check_warn_return(bmcr, "Error reading MII_BMCR"); + timeout++; + } while ((bmcr & MII_BMCR) && (timeout < 100)); + + if (timeout >= 100) { + netdev_warn(dev->net, "timeout on PHY Reset"); + return -EIO; + } + + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | + ADVERTISE_PAUSE_ASYM); + + /* read to clear */ + smsc75xx_mdio_read(dev->net, dev->mii.phy_id, PHY_INT_SRC); + check_warn_return(bmcr, "Error reading PHY_INT_SRC"); + + smsc75xx_mdio_write(dev->net, dev->mii.phy_id, PHY_INT_MASK, + PHY_INT_MASK_DEFAULT); + mii_nway_restart(&dev->mii); + + netif_dbg(dev, ifup, dev->net, "phy initialised successfully"); + return 0; +} + +static int smsc75xx_set_rx_max_frame_length(struct usbnet *dev, int size) +{ + int ret = 0; + u32 buf; + bool rxenabled; + + ret = smsc75xx_read_reg(dev, MAC_RX, &buf); + check_warn_return(ret, "Failed to read MAC_RX: %d", ret); + + rxenabled = ((buf & MAC_RX_RXEN) != 0); + + if (rxenabled) { + buf &= ~MAC_RX_RXEN; + ret = smsc75xx_write_reg(dev, MAC_RX, buf); + check_warn_return(ret, "Failed to write MAC_RX: %d", ret); + } + + /* add 4 to size for FCS */ + buf &= ~MAC_RX_MAX_SIZE; + buf |= (((size + 4) << MAC_RX_MAX_SIZE_SHIFT) & MAC_RX_MAX_SIZE); + + ret = smsc75xx_write_reg(dev, MAC_RX, buf); + check_warn_return(ret, "Failed to write MAC_RX: %d", ret); + + if (rxenabled) { + buf |= MAC_RX_RXEN; + ret = smsc75xx_write_reg(dev, MAC_RX, buf); + check_warn_return(ret, "Failed to write MAC_RX: %d", ret); + } + + return 0; +} + +static int smsc75xx_change_mtu(struct net_device *netdev, int new_mtu) +{ + struct usbnet *dev = netdev_priv(netdev); + + int ret = smsc75xx_set_rx_max_frame_length(dev, new_mtu); + check_warn_return(ret, "Failed to set mac rx frame length"); + + return usbnet_change_mtu(netdev, new_mtu); +} + +static int smsc75xx_reset(struct usbnet *dev) +{ + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + u32 buf; + int ret = 0, timeout; + + netif_dbg(dev, ifup, dev->net, "entering smsc75xx_reset"); + + ret = smsc75xx_read_reg(dev, HW_CFG, &buf); + check_warn_return(ret, "Failed to read HW_CFG: %d", ret); + + buf |= HW_CFG_LRST; + + ret = smsc75xx_write_reg(dev, HW_CFG, buf); + check_warn_return(ret, "Failed to write HW_CFG: %d", ret); + + timeout = 0; + do { + msleep(10); + ret = smsc75xx_read_reg(dev, HW_CFG, &buf); + check_warn_return(ret, "Failed to read HW_CFG: %d", ret); + timeout++; + } while ((buf & HW_CFG_LRST) && (timeout < 100)); + + if (timeout >= 100) { + netdev_warn(dev->net, "timeout on completion of Lite Reset"); + return -EIO; + } + + netif_dbg(dev, ifup, dev->net, "Lite reset complete, resetting PHY"); + + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); + check_warn_return(ret, "Failed to read PMT_CTL: %d", ret); + + buf |= PMT_CTL_PHY_RST; + + ret = smsc75xx_write_reg(dev, PMT_CTL, buf); + check_warn_return(ret, "Failed to write PMT_CTL: %d", ret); + + timeout = 0; + do { + msleep(10); + ret = smsc75xx_read_reg(dev, PMT_CTL, &buf); + check_warn_return(ret, "Failed to read PMT_CTL: %d", ret); + timeout++; + } while ((buf & PMT_CTL_PHY_RST) && (timeout < 100)); + + if (timeout >= 100) { + netdev_warn(dev->net, "timeout waiting for PHY Reset"); + return -EIO; + } + + netif_dbg(dev, ifup, dev->net, "PHY reset complete"); + + smsc75xx_init_mac_address(dev); + + ret = smsc75xx_set_mac_address(dev); + check_warn_return(ret, "Failed to set mac address"); + + netif_dbg(dev, ifup, dev->net, "MAC Address: %pM", dev->net->dev_addr); + + ret = smsc75xx_read_reg(dev, HW_CFG, &buf); + check_warn_return(ret, "Failed to read HW_CFG: %d", ret); + + netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG : 0x%08x", buf); + + buf |= HW_CFG_BIR; + + ret = smsc75xx_write_reg(dev, HW_CFG, buf); + check_warn_return(ret, "Failed to write HW_CFG: %d", ret); + + ret = smsc75xx_read_reg(dev, HW_CFG, &buf); + check_warn_return(ret, "Failed to read HW_CFG: %d", ret); + + netif_dbg(dev, ifup, dev->net, "Read Value from HW_CFG after " + "writing HW_CFG_BIR: 0x%08x", buf); + + if (!turbo_mode) { + buf = 0; + dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE; + } else if (dev->udev->speed == USB_SPEED_HIGH) { + buf = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE; + dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE; + } else { + buf = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE; + dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE; + } + + netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld", + (ulong)dev->rx_urb_size); + + ret = smsc75xx_write_reg(dev, BURST_CAP, buf); + check_warn_return(ret, "Failed to write BURST_CAP: %d", ret); + + ret = smsc75xx_read_reg(dev, BURST_CAP, &buf); + check_warn_return(ret, "Failed to read BURST_CAP: %d", ret); + + netif_dbg(dev, ifup, dev->net, + "Read Value from BURST_CAP after writing: 0x%08x", buf); + + ret = smsc75xx_write_reg(dev, BULK_IN_DLY, DEFAULT_BULK_IN_DELAY); + check_warn_return(ret, "Failed to write BULK_IN_DLY: %d", ret); + + ret = smsc75xx_read_reg(dev, BULK_IN_DLY, &buf); + check_warn_return(ret, "Failed to read BULK_IN_DLY: %d", ret); + + netif_dbg(dev, ifup, dev->net, + "Read Value from BULK_IN_DLY after writing: 0x%08x", buf); + + if (turbo_mode) { + ret = smsc75xx_read_reg(dev, HW_CFG, &buf); + check_warn_return(ret, "Failed to read HW_CFG: %d", ret); + + netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x", buf); + + buf |= (HW_CFG_MEF | HW_CFG_BCE); + + ret = smsc75xx_write_reg(dev, HW_CFG, buf); + check_warn_return(ret, "Failed to write HW_CFG: %d", ret); + + ret = smsc75xx_read_reg(dev, HW_CFG, &buf); + check_warn_return(ret, "Failed to read HW_CFG: %d", ret); + + netif_dbg(dev, ifup, dev->net, "HW_CFG: 0x%08x", buf); + } + + /* set FIFO sizes */ + buf = (MAX_RX_FIFO_SIZE - 512) / 512; + ret = smsc75xx_write_reg(dev, FCT_RX_FIFO_END, buf); + check_warn_return(ret, "Failed to write FCT_RX_FIFO_END: %d", ret); + + netif_dbg(dev, ifup, dev->net, "FCT_RX_FIFO_END set to 0x%08x", buf); + + buf = (MAX_TX_FIFO_SIZE - 512) / 512; + ret = smsc75xx_write_reg(dev, FCT_TX_FIFO_END, buf); + check_warn_return(ret, "Failed to write FCT_TX_FIFO_END: %d", ret); + + netif_dbg(dev, ifup, dev->net, "FCT_TX_FIFO_END set to 0x%08x", buf); + + ret = smsc75xx_write_reg(dev, INT_STS, INT_STS_CLEAR_ALL); + check_warn_return(ret, "Failed to write INT_STS: %d", ret); + + ret = smsc75xx_read_reg(dev, ID_REV, &buf); + check_warn_return(ret, "Failed to read ID_REV: %d", ret); + + netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x", buf); + + /* Configure GPIO pins as LED outputs */ + ret = smsc75xx_read_reg(dev, LED_GPIO_CFG, &buf); + check_warn_return(ret, "Failed to read LED_GPIO_CFG: %d", ret); + + buf &= ~(LED_GPIO_CFG_LED2_FUN_SEL | LED_GPIO_CFG_LED10_FUN_SEL); + buf |= LED_GPIO_CFG_LEDGPIO_EN | LED_GPIO_CFG_LED2_FUN_SEL; + + ret = smsc75xx_write_reg(dev, LED_GPIO_CFG, buf); + check_warn_return(ret, "Failed to write LED_GPIO_CFG: %d", ret); + + ret = smsc75xx_write_reg(dev, FLOW, 0); + check_warn_return(ret, "Failed to write FLOW: %d", ret); + + ret = smsc75xx_write_reg(dev, FCT_FLOW, 0); + check_warn_return(ret, "Failed to write FCT_FLOW: %d", ret); + + /* Don't need rfe_ctl_lock during initialisation */ + ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl); + check_warn_return(ret, "Failed to read RFE_CTL: %d", ret); + + pdata->rfe_ctl |= RFE_CTL_AB | RFE_CTL_DPF; + + ret = smsc75xx_write_reg(dev, RFE_CTL, pdata->rfe_ctl); + check_warn_return(ret, "Failed to write RFE_CTL: %d", ret); + + ret = smsc75xx_read_reg(dev, RFE_CTL, &pdata->rfe_ctl); + check_warn_return(ret, "Failed to read RFE_CTL: %d", ret); + + netif_dbg(dev, ifup, dev->net, "RFE_CTL set to 0x%08x", pdata->rfe_ctl); + + /* Enable or disable checksum offload engines */ + ethtool_op_set_tx_hw_csum(dev->net, DEFAULT_TX_CSUM_ENABLE); + ret = smsc75xx_set_rx_csum_offload(dev); + check_warn_return(ret, "Failed to set rx csum offload: %d", ret); + + smsc75xx_ethtool_set_tso(dev->net, DEFAULT_TSO_ENABLE); + + smsc75xx_set_multicast(dev->net); + + ret = smsc75xx_phy_initialize(dev); + check_warn_return(ret, "Failed to initialize PHY: %d", ret); + + ret = smsc75xx_read_reg(dev, INT_EP_CTL, &buf); + check_warn_return(ret, "Failed to read INT_EP_CTL: %d", ret); + + /* enable PHY interrupts */ + buf |= INT_ENP_PHY_INT; + + ret = smsc75xx_write_reg(dev, INT_EP_CTL, buf); + check_warn_return(ret, "Failed to write INT_EP_CTL: %d", ret); + + ret = smsc75xx_read_reg(dev, MAC_TX, &buf); + check_warn_return(ret, "Failed to read MAC_TX: %d", ret); + + buf |= MAC_TX_TXEN; + + ret = smsc75xx_write_reg(dev, MAC_TX, buf); + check_warn_return(ret, "Failed to write MAC_TX: %d", ret); + + netif_dbg(dev, ifup, dev->net, "MAC_TX set to 0x%08x", buf); + + ret = smsc75xx_read_reg(dev, FCT_TX_CTL, &buf); + check_warn_return(ret, "Failed to read FCT_TX_CTL: %d", ret); + + buf |= FCT_TX_CTL_EN; + + ret = smsc75xx_write_reg(dev, FCT_TX_CTL, buf); + check_warn_return(ret, "Failed to write FCT_TX_CTL: %d", ret); + + netif_dbg(dev, ifup, dev->net, "FCT_TX_CTL set to 0x%08x", buf); + + ret = smsc75xx_set_rx_max_frame_length(dev, 1514); + check_warn_return(ret, "Failed to set max rx frame length"); + + ret = smsc75xx_read_reg(dev, MAC_RX, &buf); + check_warn_return(ret, "Failed to read MAC_RX: %d", ret); + + buf |= MAC_RX_RXEN; + + ret = smsc75xx_write_reg(dev, MAC_RX, buf); + check_warn_return(ret, "Failed to write MAC_RX: %d", ret); + + netif_dbg(dev, ifup, dev->net, "MAC_RX set to 0x%08x", buf); + + ret = smsc75xx_read_reg(dev, FCT_RX_CTL, &buf); + check_warn_return(ret, "Failed to read FCT_RX_CTL: %d", ret); + + buf |= FCT_RX_CTL_EN; + + ret = smsc75xx_write_reg(dev, FCT_RX_CTL, buf); + check_warn_return(ret, "Failed to write FCT_RX_CTL: %d", ret); + + netif_dbg(dev, ifup, dev->net, "FCT_RX_CTL set to 0x%08x", buf); + + netif_dbg(dev, ifup, dev->net, "smsc75xx_reset, return 0"); + return 0; +} + +static const struct net_device_ops smsc75xx_netdev_ops = { + .ndo_open = usbnet_open, + .ndo_stop = usbnet_stop, + .ndo_start_xmit = usbnet_start_xmit, + .ndo_tx_timeout = usbnet_tx_timeout, + .ndo_change_mtu = smsc75xx_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = smsc75xx_ioctl, + .ndo_set_multicast_list = smsc75xx_set_multicast, +}; + +static int smsc75xx_bind(struct usbnet *dev, struct usb_interface *intf) +{ + struct smsc75xx_priv *pdata = NULL; + int ret; + + printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n"); + + ret = usbnet_get_endpoints(dev, intf); + check_warn_return(ret, "usbnet_get_endpoints failed: %d", ret); + + dev->data[0] = (unsigned long)kzalloc(sizeof(struct smsc75xx_priv), + GFP_KERNEL); + + pdata = (struct smsc75xx_priv *)(dev->data[0]); + if (!pdata) { + netdev_warn(dev->net, "Unable to allocate smsc75xx_priv"); + return -ENOMEM; + } + + pdata->dev = dev; + + spin_lock_init(&pdata->rfe_ctl_lock); + mutex_init(&pdata->dataport_mutex); + + INIT_WORK(&pdata->set_multicast, smsc75xx_deferred_multicast_write); + + pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; + + /* We have to advertise SG otherwise TSO cannot be enabled */ + dev->net->features |= NETIF_F_SG; + + /* Init all registers */ + ret = smsc75xx_reset(dev); + + dev->net->netdev_ops = &smsc75xx_netdev_ops; + dev->net->ethtool_ops = &smsc75xx_ethtool_ops; + dev->net->flags |= IFF_MULTICAST; + dev->net->hard_header_len += SMSC75XX_TX_OVERHEAD; + return 0; +} + +static void smsc75xx_unbind(struct usbnet *dev, struct usb_interface *intf) +{ + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + if (pdata) { + netif_dbg(dev, ifdown, dev->net, "free pdata"); + kfree(pdata); + pdata = NULL; + dev->data[0] = 0; + } +} + +static void smsc75xx_rx_csum_offload(struct sk_buff *skb, u32 rx_cmd_a, + u32 rx_cmd_b) +{ + if (unlikely(rx_cmd_a & RX_CMD_A_LCSM)) { + skb->ip_summed = CHECKSUM_NONE; + } else { + skb->csum = ntohs((u16)(rx_cmd_b >> RX_CMD_B_CSUM_SHIFT)); + skb->ip_summed = CHECKSUM_COMPLETE; + } +} + +static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + struct smsc75xx_priv *pdata = (struct smsc75xx_priv *)(dev->data[0]); + + while (skb->len > 0) { + u32 rx_cmd_a, rx_cmd_b, align_count, size; + struct sk_buff *ax_skb; + unsigned char *packet; + + memcpy(&rx_cmd_a, skb->data, sizeof(rx_cmd_a)); + le32_to_cpus(&rx_cmd_a); + skb_pull(skb, 4); + + memcpy(&rx_cmd_b, skb->data, sizeof(rx_cmd_b)); + le32_to_cpus(&rx_cmd_b); + skb_pull(skb, 4 + NET_IP_ALIGN); + + packet = skb->data; + + /* get the packet length */ + size = (rx_cmd_a & RX_CMD_A_LEN) - NET_IP_ALIGN; + align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4; + + if (unlikely(rx_cmd_a & RX_CMD_A_RED)) { + netif_dbg(dev, rx_err, dev->net, + "Error rx_cmd_a=0x%08x", rx_cmd_a); + dev->net->stats.rx_errors++; + dev->net->stats.rx_dropped++; + + if (rx_cmd_a & RX_CMD_A_FCS) + dev->net->stats.rx_crc_errors++; + else if (rx_cmd_a & (RX_CMD_A_LONG | RX_CMD_A_RUNT)) + dev->net->stats.rx_frame_errors++; + } else { + /* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */ + if (unlikely(size > (ETH_FRAME_LEN + 12))) { + netif_dbg(dev, rx_err, dev->net, + "size err rx_cmd_a=0x%08x", rx_cmd_a); + return 0; + } + + /* last frame in this batch */ + if (skb->len == size) { + if (pdata->use_rx_csum) + smsc75xx_rx_csum_offload(skb, rx_cmd_a, + rx_cmd_b); + else + skb->ip_summed = CHECKSUM_NONE; + + skb_trim(skb, skb->len - 4); /* remove fcs */ + skb->truesize = size + sizeof(struct sk_buff); + + return 1; + } + + ax_skb = skb_clone(skb, GFP_ATOMIC); + if (unlikely(!ax_skb)) { + netdev_warn(dev->net, "Error allocating skb"); + return 0; + } + + ax_skb->len = size; + ax_skb->data = packet; + skb_set_tail_pointer(ax_skb, size); + + if (pdata->use_rx_csum) + smsc75xx_rx_csum_offload(ax_skb, rx_cmd_a, + rx_cmd_b); + else + ax_skb->ip_summed = CHECKSUM_NONE; + + skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ + ax_skb->truesize = size + sizeof(struct sk_buff); + + usbnet_skb_return(dev, ax_skb); + } + + skb_pull(skb, size); + + /* padding bytes before the next frame starts */ + if (skb->len) + skb_pull(skb, align_count); + } + + if (unlikely(skb->len < 0)) { + netdev_warn(dev->net, "invalid rx length<0 %d", skb->len); + return 0; + } + + return 1; +} + +static struct sk_buff *smsc75xx_tx_fixup(struct usbnet *dev, + struct sk_buff *skb, gfp_t flags) +{ + u32 tx_cmd_a, tx_cmd_b; + + skb_linearize(skb); + + if (skb_headroom(skb) < SMSC75XX_TX_OVERHEAD) { + struct sk_buff *skb2 = + skb_copy_expand(skb, SMSC75XX_TX_OVERHEAD, 0, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } + + tx_cmd_a = (u32)(skb->len & TX_CMD_A_LEN) | TX_CMD_A_FCS; + + if (skb->ip_summed == CHECKSUM_PARTIAL) + tx_cmd_a |= TX_CMD_A_IPE | TX_CMD_A_TPE; + + if (skb_is_gso(skb)) { + u16 mss = max(skb_shinfo(skb)->gso_size, TX_MSS_MIN); + tx_cmd_b = (mss << TX_CMD_B_MSS_SHIFT) & TX_CMD_B_MSS; + + tx_cmd_a |= TX_CMD_A_LSO; + } else { + tx_cmd_b = 0; + } + + skb_push(skb, 4); + cpu_to_le32s(&tx_cmd_b); + memcpy(skb->data, &tx_cmd_b, 4); + + skb_push(skb, 4); + cpu_to_le32s(&tx_cmd_a); + memcpy(skb->data, &tx_cmd_a, 4); + + return skb; +} + +static const struct driver_info smsc75xx_info = { + .description = "smsc75xx USB 2.0 Gigabit Ethernet", + .bind = smsc75xx_bind, + .unbind = smsc75xx_unbind, + .link_reset = smsc75xx_link_reset, + .reset = smsc75xx_reset, + .rx_fixup = smsc75xx_rx_fixup, + .tx_fixup = smsc75xx_tx_fixup, + .status = smsc75xx_status, + .flags = FLAG_ETHER | FLAG_SEND_ZLP, +}; + +static const struct usb_device_id products[] = { + { + /* SMSC7500 USB Gigabit Ethernet Device */ + USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7500), + .driver_info = (unsigned long) &smsc75xx_info, + }, + { + /* SMSC7500 USB Gigabit Ethernet Device */ + USB_DEVICE(USB_VENDOR_ID_SMSC, USB_PRODUCT_ID_LAN7505), + .driver_info = (unsigned long) &smsc75xx_info, + }, + { }, /* END */ +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver smsc75xx_driver = { + .name = SMSC_CHIPNAME, + .id_table = products, + .probe = usbnet_probe, + .suspend = usbnet_suspend, + .resume = usbnet_resume, + .disconnect = usbnet_disconnect, +}; + +static int __init smsc75xx_init(void) +{ + return usb_register(&smsc75xx_driver); +} +module_init(smsc75xx_init); + +static void __exit smsc75xx_exit(void) +{ + usb_deregister(&smsc75xx_driver); +} +module_exit(smsc75xx_exit); + +MODULE_AUTHOR("Nancy Lin"); +MODULE_AUTHOR("Steve Glendinning <steve.glendinning@smsc.com>"); +MODULE_DESCRIPTION("SMSC75XX USB 2.0 Gigabit Ethernet Devices"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/smsc75xx.h b/drivers/net/usb/smsc75xx.h new file mode 100644 index 00000000000..16e98c77834 --- /dev/null +++ b/drivers/net/usb/smsc75xx.h @@ -0,0 +1,421 @@ + /*************************************************************************** + * + * Copyright (C) 2007-2010 SMSC + * + * 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 _SMSC75XX_H +#define _SMSC75XX_H + +/* Tx command words */ +#define TX_CMD_A_LSO (0x08000000) +#define TX_CMD_A_IPE (0x04000000) +#define TX_CMD_A_TPE (0x02000000) +#define TX_CMD_A_IVTG (0x01000000) +#define TX_CMD_A_RVTG (0x00800000) +#define TX_CMD_A_FCS (0x00400000) +#define TX_CMD_A_LEN (0x000FFFFF) + +#define TX_CMD_B_MSS (0x3FFF0000) +#define TX_CMD_B_MSS_SHIFT (16) +#define TX_MSS_MIN ((u16)8) +#define TX_CMD_B_VTAG (0x0000FFFF) + +/* Rx command words */ +#define RX_CMD_A_ICE (0x80000000) +#define RX_CMD_A_TCE (0x40000000) +#define RX_CMD_A_IPV (0x20000000) +#define RX_CMD_A_PID (0x18000000) +#define RX_CMD_A_PID_NIP (0x00000000) +#define RX_CMD_A_PID_TCP (0x08000000) +#define RX_CMD_A_PID_UDP (0x10000000) +#define RX_CMD_A_PID_PP (0x18000000) +#define RX_CMD_A_PFF (0x04000000) +#define RX_CMD_A_BAM (0x02000000) +#define RX_CMD_A_MAM (0x01000000) +#define RX_CMD_A_FVTG (0x00800000) +#define RX_CMD_A_RED (0x00400000) +#define RX_CMD_A_RWT (0x00200000) +#define RX_CMD_A_RUNT (0x00100000) +#define RX_CMD_A_LONG (0x00080000) +#define RX_CMD_A_RXE (0x00040000) +#define RX_CMD_A_DRB (0x00020000) +#define RX_CMD_A_FCS (0x00010000) +#define RX_CMD_A_UAM (0x00008000) +#define RX_CMD_A_LCSM (0x00004000) +#define RX_CMD_A_LEN (0x00003FFF) + +#define RX_CMD_B_CSUM (0xFFFF0000) +#define RX_CMD_B_CSUM_SHIFT (16) +#define RX_CMD_B_VTAG (0x0000FFFF) + +/* SCSRs */ +#define ID_REV (0x0000) + +#define FPGA_REV (0x0004) + +#define BOND_CTL (0x0008) + +#define INT_STS (0x000C) +#define INT_STS_RDFO_INT (0x00400000) +#define INT_STS_TXE_INT (0x00200000) +#define INT_STS_MACRTO_INT (0x00100000) +#define INT_STS_TX_DIS_INT (0x00080000) +#define INT_STS_RX_DIS_INT (0x00040000) +#define INT_STS_PHY_INT_ (0x00020000) +#define INT_STS_MAC_ERR_INT (0x00008000) +#define INT_STS_TDFU (0x00004000) +#define INT_STS_TDFO (0x00002000) +#define INT_STS_GPIOS (0x00000FFF) +#define INT_STS_CLEAR_ALL (0xFFFFFFFF) + +#define HW_CFG (0x0010) +#define HW_CFG_SMDET_STS (0x00008000) +#define HW_CFG_SMDET_EN (0x00004000) +#define HW_CFG_EEM (0x00002000) +#define HW_CFG_RST_PROTECT (0x00001000) +#define HW_CFG_PORT_SWAP (0x00000800) +#define HW_CFG_PHY_BOOST (0x00000600) +#define HW_CFG_PHY_BOOST_NORMAL (0x00000000) +#define HW_CFG_PHY_BOOST_4 (0x00002000) +#define HW_CFG_PHY_BOOST_8 (0x00004000) +#define HW_CFG_PHY_BOOST_12 (0x00006000) +#define HW_CFG_LEDB (0x00000100) +#define HW_CFG_BIR (0x00000080) +#define HW_CFG_SBP (0x00000040) +#define HW_CFG_IME (0x00000020) +#define HW_CFG_MEF (0x00000010) +#define HW_CFG_ETC (0x00000008) +#define HW_CFG_BCE (0x00000004) +#define HW_CFG_LRST (0x00000002) +#define HW_CFG_SRST (0x00000001) + +#define PMT_CTL (0x0014) +#define PMT_CTL_PHY_PWRUP (0x00000400) +#define PMT_CTL_RES_CLR_WKP_EN (0x00000100) +#define PMT_CTL_DEV_RDY (0x00000080) +#define PMT_CTL_SUS_MODE (0x00000060) +#define PMT_CTL_SUS_MODE_0 (0x00000000) +#define PMT_CTL_SUS_MODE_1 (0x00000020) +#define PMT_CTL_SUS_MODE_2 (0x00000040) +#define PMT_CTL_SUS_MODE_3 (0x00000060) +#define PMT_CTL_PHY_RST (0x00000010) +#define PMT_CTL_WOL_EN (0x00000008) +#define PMT_CTL_ED_EN (0x00000004) +#define PMT_CTL_WUPS (0x00000003) +#define PMT_CTL_WUPS_NO (0x00000000) +#define PMT_CTL_WUPS_ED (0x00000001) +#define PMT_CTL_WUPS_WOL (0x00000002) +#define PMT_CTL_WUPS_MULTI (0x00000003) + +#define LED_GPIO_CFG (0x0018) +#define LED_GPIO_CFG_LED2_FUN_SEL (0x80000000) +#define LED_GPIO_CFG_LED10_FUN_SEL (0x40000000) +#define LED_GPIO_CFG_LEDGPIO_EN (0x0000F000) +#define LED_GPIO_CFG_LEDGPIO_EN_0 (0x00001000) +#define LED_GPIO_CFG_LEDGPIO_EN_1 (0x00002000) +#define LED_GPIO_CFG_LEDGPIO_EN_2 (0x00004000) +#define LED_GPIO_CFG_LEDGPIO_EN_3 (0x00008000) +#define LED_GPIO_CFG_GPBUF (0x00000F00) +#define LED_GPIO_CFG_GPBUF_0 (0x00000100) +#define LED_GPIO_CFG_GPBUF_1 (0x00000200) +#define LED_GPIO_CFG_GPBUF_2 (0x00000400) +#define LED_GPIO_CFG_GPBUF_3 (0x00000800) +#define LED_GPIO_CFG_GPDIR (0x000000F0) +#define LED_GPIO_CFG_GPDIR_0 (0x00000010) +#define LED_GPIO_CFG_GPDIR_1 (0x00000020) +#define LED_GPIO_CFG_GPDIR_2 (0x00000040) +#define LED_GPIO_CFG_GPDIR_3 (0x00000080) +#define LED_GPIO_CFG_GPDATA (0x0000000F) +#define LED_GPIO_CFG_GPDATA_0 (0x00000001) +#define LED_GPIO_CFG_GPDATA_1 (0x00000002) +#define LED_GPIO_CFG_GPDATA_2 (0x00000004) +#define LED_GPIO_CFG_GPDATA_3 (0x00000008) + +#define GPIO_CFG (0x001C) +#define GPIO_CFG_SHIFT (24) +#define GPIO_CFG_GPEN (0xFF000000) +#define GPIO_CFG_GPBUF (0x00FF0000) +#define GPIO_CFG_GPDIR (0x0000FF00) +#define GPIO_CFG_GPDATA (0x000000FF) + +#define GPIO_WAKE (0x0020) +#define GPIO_WAKE_PHY_LINKUP_EN (0x80000000) +#define GPIO_WAKE_POL (0x0FFF0000) +#define GPIO_WAKE_POL_SHIFT (16) +#define GPIO_WAKE_WK (0x00000FFF) + +#define DP_SEL (0x0024) +#define DP_SEL_DPRDY (0x80000000) +#define DP_SEL_RSEL (0x0000000F) +#define DP_SEL_URX (0x00000000) +#define DP_SEL_VHF (0x00000001) +#define DP_SEL_VHF_HASH_LEN (16) +#define DP_SEL_VHF_VLAN_LEN (128) +#define DP_SEL_LSO_HEAD (0x00000002) +#define DP_SEL_FCT_RX (0x00000003) +#define DP_SEL_FCT_TX (0x00000004) +#define DP_SEL_DESCRIPTOR (0x00000005) +#define DP_SEL_WOL (0x00000006) + +#define DP_CMD (0x0028) +#define DP_CMD_WRITE (0x01) +#define DP_CMD_READ (0x00) + +#define DP_ADDR (0x002C) + +#define DP_DATA (0x0030) + +#define BURST_CAP (0x0034) +#define BURST_CAP_MASK (0x0000000F) + +#define INT_EP_CTL (0x0038) +#define INT_EP_CTL_INTEP_ON (0x80000000) +#define INT_EP_CTL_RDFO_EN (0x00400000) +#define INT_EP_CTL_TXE_EN (0x00200000) +#define INT_EP_CTL_MACROTO_EN (0x00100000) +#define INT_EP_CTL_TX_DIS_EN (0x00080000) +#define INT_EP_CTL_RX_DIS_EN (0x00040000) +#define INT_EP_CTL_PHY_EN_ (0x00020000) +#define INT_EP_CTL_MAC_ERR_EN (0x00008000) +#define INT_EP_CTL_TDFU_EN (0x00004000) +#define INT_EP_CTL_TDFO_EN (0x00002000) +#define INT_EP_CTL_RX_FIFO_EN (0x00001000) +#define INT_EP_CTL_GPIOX_EN (0x00000FFF) + +#define BULK_IN_DLY (0x003C) +#define BULK_IN_DLY_MASK (0xFFFF) + +#define E2P_CMD (0x0040) +#define E2P_CMD_BUSY (0x80000000) +#define E2P_CMD_MASK (0x70000000) +#define E2P_CMD_READ (0x00000000) +#define E2P_CMD_EWDS (0x10000000) +#define E2P_CMD_EWEN (0x20000000) +#define E2P_CMD_WRITE (0x30000000) +#define E2P_CMD_WRAL (0x40000000) +#define E2P_CMD_ERASE (0x50000000) +#define E2P_CMD_ERAL (0x60000000) +#define E2P_CMD_RELOAD (0x70000000) +#define E2P_CMD_TIMEOUT (0x00000400) +#define E2P_CMD_LOADED (0x00000200) +#define E2P_CMD_ADDR (0x000001FF) + +#define MAX_EEPROM_SIZE (512) + +#define E2P_DATA (0x0044) +#define E2P_DATA_MASK_ (0x000000FF) + +#define RFE_CTL (0x0060) +#define RFE_CTL_TCPUDP_CKM (0x00001000) +#define RFE_CTL_IP_CKM (0x00000800) +#define RFE_CTL_AB (0x00000400) +#define RFE_CTL_AM (0x00000200) +#define RFE_CTL_AU (0x00000100) +#define RFE_CTL_VS (0x00000080) +#define RFE_CTL_UF (0x00000040) +#define RFE_CTL_VF (0x00000020) +#define RFE_CTL_SPF (0x00000010) +#define RFE_CTL_MHF (0x00000008) +#define RFE_CTL_DHF (0x00000004) +#define RFE_CTL_DPF (0x00000002) +#define RFE_CTL_RST_RF (0x00000001) + +#define VLAN_TYPE (0x0064) +#define VLAN_TYPE_MASK (0x0000FFFF) + +#define FCT_RX_CTL (0x0090) +#define FCT_RX_CTL_EN (0x80000000) +#define FCT_RX_CTL_RST (0x40000000) +#define FCT_RX_CTL_SBF (0x02000000) +#define FCT_RX_CTL_OVERFLOW (0x01000000) +#define FCT_RX_CTL_FRM_DROP (0x00800000) +#define FCT_RX_CTL_RX_NOT_EMPTY (0x00400000) +#define FCT_RX_CTL_RX_EMPTY (0x00200000) +#define FCT_RX_CTL_RX_DISABLED (0x00100000) +#define FCT_RX_CTL_RXUSED (0x0000FFFF) + +#define FCT_TX_CTL (0x0094) +#define FCT_TX_CTL_EN (0x80000000) +#define FCT_TX_CTL_RST (0x40000000) +#define FCT_TX_CTL_TX_NOT_EMPTY (0x00400000) +#define FCT_TX_CTL_TX_EMPTY (0x00200000) +#define FCT_TX_CTL_TX_DISABLED (0x00100000) +#define FCT_TX_CTL_TXUSED (0x0000FFFF) + +#define FCT_RX_FIFO_END (0x0098) +#define FCT_RX_FIFO_END_MASK (0x0000007F) + +#define FCT_TX_FIFO_END (0x009C) +#define FCT_TX_FIFO_END_MASK (0x0000003F) + +#define FCT_FLOW (0x00A0) +#define FCT_FLOW_THRESHOLD_OFF (0x00007F00) +#define FCT_FLOW_THRESHOLD_OFF_SHIFT (8) +#define FCT_FLOW_THRESHOLD_ON (0x0000007F) + +/* MAC CSRs */ +#define MAC_CR (0x100) +#define MAC_CR_ADP (0x00002000) +#define MAC_CR_ADD (0x00001000) +#define MAC_CR_ASD (0x00000800) +#define MAC_CR_INT_LOOP (0x00000400) +#define MAC_CR_BOLMT (0x000000C0) +#define MAC_CR_FDPX (0x00000008) +#define MAC_CR_CFG (0x00000006) +#define MAC_CR_CFG_10 (0x00000000) +#define MAC_CR_CFG_100 (0x00000002) +#define MAC_CR_CFG_1000 (0x00000004) +#define MAC_CR_RST (0x00000001) + +#define MAC_RX (0x104) +#define MAC_RX_MAX_SIZE (0x3FFF0000) +#define MAC_RX_MAX_SIZE_SHIFT (16) +#define MAC_RX_FCS_STRIP (0x00000010) +#define MAC_RX_FSE (0x00000004) +#define MAC_RX_RXD (0x00000002) +#define MAC_RX_RXEN (0x00000001) + +#define MAC_TX (0x108) +#define MAC_TX_BFCS (0x00000004) +#define MAC_TX_TXD (0x00000002) +#define MAC_TX_TXEN (0x00000001) + +#define FLOW (0x10C) +#define FLOW_FORCE_FC (0x80000000) +#define FLOW_TX_FCEN (0x40000000) +#define FLOW_RX_FCEN (0x20000000) +#define FLOW_FPF (0x10000000) +#define FLOW_PAUSE_TIME (0x0000FFFF) + +#define RAND_SEED (0x110) +#define RAND_SEED_MASK (0x0000FFFF) + +#define ERR_STS (0x114) +#define ERR_STS_FCS_ERR (0x00000100) +#define ERR_STS_LFRM_ERR (0x00000080) +#define ERR_STS_RUNT_ERR (0x00000040) +#define ERR_STS_COLLISION_ERR (0x00000010) +#define ERR_STS_ALIGN_ERR (0x00000008) +#define ERR_STS_URUN_ERR (0x00000004) + +#define RX_ADDRH (0x118) +#define RX_ADDRH_MASK (0x0000FFFF) + +#define RX_ADDRL (0x11C) + +#define MII_ACCESS (0x120) +#define MII_ACCESS_PHY_ADDR (0x0000F800) +#define MII_ACCESS_PHY_ADDR_SHIFT (11) +#define MII_ACCESS_REG_ADDR (0x000007C0) +#define MII_ACCESS_REG_ADDR_SHIFT (6) +#define MII_ACCESS_READ (0x00000000) +#define MII_ACCESS_WRITE (0x00000002) +#define MII_ACCESS_BUSY (0x00000001) + +#define MII_DATA (0x124) +#define MII_DATA_MASK (0x0000FFFF) + +#define WUCSR (0x140) +#define WUCSR_PFDA_FR (0x00000080) +#define WUCSR_WUFR (0x00000040) +#define WUCSR_MPR (0x00000020) +#define WUCSR_BCAST_FR (0x00000010) +#define WUCSR_PFDA_EN (0x00000008) +#define WUCSR_WUEN (0x00000004) +#define WUCSR_MPEN (0x00000002) +#define WUCSR_BCST_EN (0x00000001) + +#define WUF_CFGX (0x144) +#define WUF_CFGX_EN (0x80000000) +#define WUF_CFGX_ATYPE (0x03000000) +#define WUF_CFGX_ATYPE_UNICAST (0x00000000) +#define WUF_CFGX_ATYPE_MULTICAST (0x02000000) +#define WUF_CFGX_ATYPE_ALL (0x03000000) +#define WUF_CFGX_PATTERN_OFFSET (0x007F0000) +#define WUF_CFGX_PATTERN_OFFSET_SHIFT (16) +#define WUF_CFGX_CRC16 (0x0000FFFF) +#define WUF_NUM (8) + +#define WUF_MASKX (0x170) +#define WUF_MASKX_AVALID (0x80000000) +#define WUF_MASKX_ATYPE (0x40000000) + +#define ADDR_FILTX (0x300) +#define ADDR_FILTX_FB_VALID (0x80000000) +#define ADDR_FILTX_FB_TYPE (0x40000000) +#define ADDR_FILTX_FB_ADDRHI (0x0000FFFF) +#define ADDR_FILTX_SB_ADDRLO (0xFFFFFFFF) + +#define WUCSR2 (0x500) +#define WUCSR2_NS_RCD (0x00000040) +#define WUCSR2_ARP_RCD (0x00000020) +#define WUCSR2_TCPSYN_RCD (0x00000010) +#define WUCSR2_NS_OFFLOAD (0x00000004) +#define WUCSR2_ARP_OFFLOAD (0x00000002) +#define WUCSR2_TCPSYN_OFFLOAD (0x00000001) + +#define WOL_FIFO_STS (0x504) + +#define IPV6_ADDRX (0x510) + +#define IPV4_ADDRX (0x590) + + +/* Vendor-specific PHY Definitions */ + +/* Mode Control/Status Register */ +#define PHY_MODE_CTRL_STS (17) +#define MODE_CTRL_STS_EDPWRDOWN ((u16)0x2000) +#define MODE_CTRL_STS_ENERGYON ((u16)0x0002) + +#define PHY_INT_SRC (29) +#define PHY_INT_SRC_ENERGY_ON ((u16)0x0080) +#define PHY_INT_SRC_ANEG_COMP ((u16)0x0040) +#define PHY_INT_SRC_REMOTE_FAULT ((u16)0x0020) +#define PHY_INT_SRC_LINK_DOWN ((u16)0x0010) + +#define PHY_INT_MASK (30) +#define PHY_INT_MASK_ENERGY_ON ((u16)0x0080) +#define PHY_INT_MASK_ANEG_COMP ((u16)0x0040) +#define PHY_INT_MASK_REMOTE_FAULT ((u16)0x0020) +#define PHY_INT_MASK_LINK_DOWN ((u16)0x0010) +#define PHY_INT_MASK_DEFAULT (PHY_INT_MASK_ANEG_COMP | \ + PHY_INT_MASK_LINK_DOWN) + +#define PHY_SPECIAL (31) +#define PHY_SPECIAL_SPD ((u16)0x001C) +#define PHY_SPECIAL_SPD_10HALF ((u16)0x0004) +#define PHY_SPECIAL_SPD_10FULL ((u16)0x0014) +#define PHY_SPECIAL_SPD_100HALF ((u16)0x0008) +#define PHY_SPECIAL_SPD_100FULL ((u16)0x0018) + +/* USB Vendor Requests */ +#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0 +#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1 +#define USB_VENDOR_REQUEST_GET_STATS 0xA2 + +/* Interrupt Endpoint status word bitfields */ +#define INT_ENP_RDFO_INT ((u32)BIT(22)) +#define INT_ENP_TXE_INT ((u32)BIT(21)) +#define INT_ENP_TX_DIS_INT ((u32)BIT(19)) +#define INT_ENP_RX_DIS_INT ((u32)BIT(18)) +#define INT_ENP_PHY_INT ((u32)BIT(17)) +#define INT_ENP_MAC_ERR_INT ((u32)BIT(15)) +#define INT_ENP_RX_FIFO_DATA_INT ((u32)BIT(12)) + +#endif /* _SMSC75XX_H */ diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index df9179a1c93..73f9a31cf94 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -709,6 +709,8 @@ static void smsc95xx_start_rx_path(struct usbnet *dev) static int smsc95xx_phy_initialize(struct usbnet *dev) { + int bmcr, timeout = 0; + /* Initialize MII structure */ dev->mii.dev = dev->net; dev->mii.mdio_read = smsc95xx_mdio_read; @@ -717,7 +719,20 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) dev->mii.reg_num_mask = 0x1f; dev->mii.phy_id = SMSC95XX_INTERNAL_PHY_ID; + /* reset phy and wait for reset to complete */ smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + + do { + msleep(10); + bmcr = smsc95xx_mdio_read(dev->net, dev->mii.phy_id, MII_BMCR); + timeout++; + } while ((bmcr & MII_BMCR) && (timeout < 100)); + + if (timeout >= 100) { + netdev_warn(dev->net, "timeout on PHY Reset"); + return -EIO; + } + smsc95xx_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); @@ -1174,9 +1189,21 @@ static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, } if (csum) { - u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); - skb_push(skb, 4); - memcpy(skb->data, &csum_preamble, 4); + if (skb->len <= 45) { + /* workaround - hardware tx checksum does not work + * properly with extremely small packets */ + long csstart = skb->csum_start - skb_headroom(skb); + __wsum calc = csum_partial(skb->data + csstart, + skb->len - csstart, 0); + *((__sum16 *)(skb->data + csstart + + skb->csum_offset)) = csum_fold(calc); + + csum = false; + } else { + u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); + skb_push(skb, 4); + memcpy(skb->data, &csum_preamble, 4); + } } skb_push(skb, 4); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index b2c8207f7bc..294b486bc3e 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1353,25 +1353,6 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) return htype; } -static bool is_pae(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr; - __le16 fc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - if (ieee80211_is_data(fc)) { - if (ieee80211_is_nullfunc(fc) || - /* Port Access Entity (IEEE 802.1X) */ - (skb->protocol == cpu_to_be16(ETH_P_PAE))) { - return true; - } - } - - return false; -} - static int get_hw_crypto_keytype(struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); @@ -1696,7 +1677,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, goto tx_done; } - if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && !is_pae(skb)) { + if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { /* * Try aggregation if it's a unicast data frame * and the destination is HT capable. diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 1ed5206721e..8c12311dbb0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -124,7 +124,7 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv, if (priv->stations[sta_id].tid[tid].tfds_in_queue >= freed) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; else { - IWL_ERR(priv, "free more than tfds_in_queue (%u:%d)\n", + IWL_DEBUG_TX(priv, "free more than tfds_in_queue (%u:%d)\n", priv->stations[sta_id].tid[tid].tfds_in_queue, freed); priv->stations[sta_id].tid[tid].tfds_in_queue = 0; diff --git a/drivers/net/wireless/wl12xx/wl1251_debugfs.c b/drivers/net/wireless/wl12xx/wl1251_debugfs.c index 0ccba57fb9f..05e4d68eb4c 100644 --- a/drivers/net/wireless/wl12xx/wl1251_debugfs.c +++ b/drivers/net/wireless/wl12xx/wl1251_debugfs.c @@ -466,7 +466,8 @@ out: void wl1251_debugfs_reset(struct wl1251 *wl) { - memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); + if (wl->stats.fw_stats != NULL) + memset(wl->stats.fw_stats, 0, sizeof(*wl->stats.fw_stats)); wl->stats.retry_count = 0; wl->stats.excessive_retries = 0; } |