From 288379f050284087578b77e04f040b57db3db3f8 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Mon, 19 Jan 2009 16:43:59 -0800 Subject: net: Remove redundant NAPI functions Following the removal of the unused struct net_device * parameter from the NAPI functions named *netif_rx_* in commit 908a7a1, they are exactly equivalent to the corresponding *napi_* functions and are therefore redundant. Signed-off-by: Ben Hutchings Acked-by: Neil Horman Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 45421c8b601..16eb9dd8528 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1642,7 +1642,7 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget) rx_ring->cq_id); if (work_done < budget) { - __netif_rx_complete(napi); + __napi_complete(napi); ql_enable_completion_interrupt(qdev, rx_ring->irq); } return work_done; @@ -1727,7 +1727,7 @@ static irqreturn_t qlge_msix_tx_isr(int irq, void *dev_id) static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id) { struct rx_ring *rx_ring = dev_id; - netif_rx_schedule(&rx_ring->napi); + napi_schedule(&rx_ring->napi); return IRQ_HANDLED; } @@ -1813,7 +1813,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) &rx_ring->rx_work, 0); else - netif_rx_schedule(&rx_ring->napi); + napi_schedule(&rx_ring->napi); work_done++; } } -- cgit v1.2.3-70-g09d2 From 0c8dfc830aadd978e461dad66c33741b71c6a0be Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 27 Jan 2009 16:22:32 -0800 Subject: net: Add skb_record_rx_queue() calls to multiqueue capable drivers. Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 2 ++ drivers/net/bnx2x_main.c | 1 + drivers/net/cxgb3/sge.c | 1 + drivers/net/igb/igb_main.c | 1 + drivers/net/ixgbe/ixgbe_main.c | 1 + drivers/net/mlx4/en_rx.c | 1 + drivers/net/myri10ge/myri10ge.c | 1 + drivers/net/niu.c | 1 + drivers/net/qlge/qlge_main.c | 1 + drivers/net/s2io.c | 1 + drivers/net/sfc/rx.c | 2 ++ 11 files changed, 13 insertions(+) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index fe575b9a9b7..49e0e51a9df 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3007,6 +3007,8 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) skb->ip_summed = CHECKSUM_UNNECESSARY; } + skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]); + #ifdef BCM_VLAN if (hw_vlan) vlan_hwaccel_receive_skb(skb, bp->vlgrp, vtag); diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 71f81c79d63..88da14c141f 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -1325,6 +1325,7 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, skb->protocol = eth_type_trans(skb, bp->dev); skb->ip_summed = CHECKSUM_UNNECESSARY; + skb_record_rx_queue(skb, queue); { struct iphdr *iph; diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index 8299fb538f2..272a0168f3e 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -1937,6 +1937,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, skb->ip_summed = CHECKSUM_UNNECESSARY; } else skb->ip_summed = CHECKSUM_NONE; + skb_record_rx_queue(skb, qs - &adap->sge.qs[0]); if (unlikely(p->vlan_valid)) { struct vlan_group *grp = pi->vlan_grp; diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index e11043d90db..bd166803671 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -3751,6 +3751,7 @@ static void igb_receive_skb(struct igb_ring *ring, u8 status, struct igb_adapter * adapter = ring->adapter; bool vlan_extracted = (adapter->vlgrp && (status & E1000_RXD_STAT_VP)); + skb_record_rx_queue(skb, ring->queue_index); if (skb->ip_summed == CHECKSUM_UNNECESSARY) { if (vlan_extracted) vlan_gro_receive(&ring->napi, adapter->vlgrp, diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 43980dc45e3..fe4a4d17c4b 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -414,6 +414,7 @@ static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector, bool is_vlan = (status & IXGBE_RXD_STAT_VP); u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan); + skb_record_rx_queue(skb, q_vector - &adapter->q_vector[0]); if (skb->ip_summed == CHECKSUM_UNNECESSARY) { if (adapter->vlgrp && is_vlan && (tag != 0)) vlan_gro_receive(napi, adapter->vlgrp, tag, skb); diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index ac55ebd2f14..a4130e76499 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -768,6 +768,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud skb->ip_summed = ip_summed; skb->protocol = eth_type_trans(skb, dev); + skb_record_rx_queue(skb, cq->ring); /* Push it up the stack */ if (priv->vlgrp && (be32_to_cpu(cqe->vlan_my_qpn) & diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index 2dacb8852dc..aea9fdaa3cd 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -1324,6 +1324,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, skb_shinfo(skb)->nr_frags = 0; } skb->protocol = eth_type_trans(skb, dev); + skb_record_rx_queue(skb, ss - &mgp->ss[0]); if (mgp->csum_flag) { if ((skb->protocol == htons(ETH_P_IP)) || diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 4a5a089fa30..2346ca6bf5b 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -3390,6 +3390,7 @@ static int niu_process_rx_pkt(struct niu *np, struct rx_ring_info *rp) rp->rx_bytes += skb->len; skb->protocol = eth_type_trans(skb, np->dev); + skb_record_rx_queue(skb, rp->rx_channel); netif_receive_skb(skb); return num_rcr; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 16eb9dd8528..4ab6e72ea95 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1436,6 +1436,7 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, qdev->stats.rx_packets++; qdev->stats.rx_bytes += skb->len; skb->protocol = eth_type_trans(skb, ndev); + skb_record_rx_queue(skb, rx_ring - &qdev->rx_ring[0]); if (qdev->vlgrp && (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V)) { QPRINTK(qdev, RX_STATUS, DEBUG, "Passing a VLAN packet upstream.\n"); diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 2a96a10fd0c..e0a353f4ec9 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -7542,6 +7542,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; send_up: + skb_record_rx_queue(skb, ring_no); queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2)); aggregate: sp->mac_control.rings[ring_no].rx_bufs_left -= 1; diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index a0345b38097..66d7fe3db3e 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -575,6 +575,8 @@ void __efx_rx_packet(struct efx_channel *channel, /* Set the SKB flags */ skb->ip_summed = CHECKSUM_NONE; + skb_record_rx_queue(skb, channel->channel); + /* Pass the packet up */ netif_receive_skb(skb); -- cgit v1.2.3-70-g09d2 From bb58b5b67c08b5fde08090917a040a07ac9d43de Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 23 Feb 2009 10:42:13 +0000 Subject: qlge: Clean up mac address and frame route settings. Setting MAC addresses and routing frames to various queues will need to be done in response to firmware events as well as during initialization. This change encapsulates the facilities into a single call that can later me made from other places. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index fd515afb1aa..3a041b6d9fe 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2958,6 +2958,24 @@ static int ql_route_initialize(struct ql_adapter *qdev) return status; } +static int ql_cam_route_initialize(struct ql_adapter *qdev) +{ + int status; + + status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr, + MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n"); + return status; + } + + status = ql_route_initialize(qdev); + if (status) + QPRINTK(qdev, IFUP, ERR, "Failed to init routing table.\n"); + + return status; +} + static int ql_adapter_initialize(struct ql_adapter *qdev) { u32 value, mask; @@ -3028,16 +3046,11 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) return status; } - status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr, - MAC_ADDR_TYPE_CAM_MAC, qdev->func); - if (status) { - QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n"); - return status; - } - - status = ql_route_initialize(qdev); + /* Set up the MAC address and frame routing filter. */ + status = ql_cam_route_initialize(qdev); if (status) { - QPRINTK(qdev, IFUP, ERR, "Failed to init routing table.\n"); + QPRINTK(qdev, IFUP, ERR, + "Failed to init CAM/Routing tables.\n"); return status; } -- cgit v1.2.3-70-g09d2 From cc288f54bbace136c08742da84712add54e4acfa Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 23 Feb 2009 10:42:14 +0000 Subject: qlge: Increase MAC addr hw sem granularity. Instead of taking/giving the semaphore repeatedly when iterating over several adderesses, we have the caller hold it until all are done. This reduces PCI bus chatter and possible waits. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_dbg.c | 9 ++++++++ drivers/net/qlge/qlge_main.c | 51 +++++++++++++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 17 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_dbg.c b/drivers/net/qlge/qlge_dbg.c index 379b895ed6e..40a70c36f5a 100644 --- a/drivers/net/qlge/qlge_dbg.c +++ b/drivers/net/qlge/qlge_dbg.c @@ -83,6 +83,10 @@ static void ql_dump_cam_entries(struct ql_adapter *qdev) { int i; u32 value[3]; + + i = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); + if (i) + return; for (i = 0; i < 4; i++) { if (ql_get_mac_addr_reg(qdev, MAC_ADDR_TYPE_CAM_MAC, i, value)) { printk(KERN_ERR PFX @@ -111,12 +115,16 @@ static void ql_dump_cam_entries(struct ql_adapter *qdev) qdev->ndev->name, i, value[1], value[0]); } } + ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); } void ql_dump_routing_entries(struct ql_adapter *qdev) { int i; u32 value; + i = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); + if (i) + return; for (i = 0; i < 16; i++) { value = 0; if (ql_get_routing_reg(qdev, i, &value)) { @@ -131,6 +139,7 @@ void ql_dump_routing_entries(struct ql_adapter *qdev) qdev->ndev->name, i, value); } } + ql_sem_unlock(qdev, SEM_RT_IDX_MASK); } void ql_dump_regs(struct ql_adapter *qdev) diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 3a041b6d9fe..d316e508d06 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -247,9 +247,6 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index, u32 offset = 0; int status; - status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); - if (status) - return status; switch (type) { case MAC_ADDR_TYPE_MULTI_MAC: case MAC_ADDR_TYPE_CAM_MAC: @@ -308,7 +305,6 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index, status = -EPERM; } exit: - ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); return status; } @@ -321,9 +317,6 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, u32 offset = 0; int status = 0; - status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); - if (status) - return status; switch (type) { case MAC_ADDR_TYPE_MULTI_MAC: case MAC_ADDR_TYPE_CAM_MAC: @@ -415,7 +408,6 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, status = -EPERM; } exit: - ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); return status; } @@ -1690,19 +1682,29 @@ static void ql_vlan_rx_add_vid(struct net_device *ndev, u16 vid) { struct ql_adapter *qdev = netdev_priv(ndev); u32 enable_bit = MAC_ADDR_E; + int status; + status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); + if (status) + return; spin_lock(&qdev->hw_lock); if (ql_set_mac_addr_reg (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) { QPRINTK(qdev, IFUP, ERR, "Failed to init vlan address.\n"); } spin_unlock(&qdev->hw_lock); + ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); } static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid) { struct ql_adapter *qdev = netdev_priv(ndev); u32 enable_bit = 0; + int status; + + status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); + if (status) + return; spin_lock(&qdev->hw_lock); if (ql_set_mac_addr_reg @@ -1710,6 +1712,7 @@ static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid) QPRINTK(qdev, IFUP, ERR, "Failed to clear vlan address.\n"); } spin_unlock(&qdev->hw_lock); + ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); } @@ -2962,8 +2965,12 @@ static int ql_cam_route_initialize(struct ql_adapter *qdev) { int status; + status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); + if (status) + return status; status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr, MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ); + ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); if (status) { QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n"); return status; @@ -3428,8 +3435,11 @@ static void qlge_set_multicast_list(struct net_device *ndev) { struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev); struct dev_mc_list *mc_ptr; - int i; + int i, status; + status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); + if (status) + return; spin_lock(&qdev->hw_lock); /* * Set or clear promiscuous mode if a @@ -3485,14 +3495,19 @@ static void qlge_set_multicast_list(struct net_device *ndev) } if (ndev->mc_count) { + status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); + if (status) + goto exit; for (i = 0, mc_ptr = ndev->mc_list; mc_ptr; i++, mc_ptr = mc_ptr->next) if (ql_set_mac_addr_reg(qdev, (u8 *) mc_ptr->dmi_addr, MAC_ADDR_TYPE_MULTI_MAC, i)) { QPRINTK(qdev, HW, ERR, "Failed to loadmulticast address.\n"); + ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); goto exit; } + ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); if (ql_set_routing_reg (qdev, RT_IDX_MCAST_MATCH_SLOT, RT_IDX_MCAST_MATCH, 1)) { QPRINTK(qdev, HW, ERR, @@ -3509,7 +3524,7 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p) { struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev); struct sockaddr *addr = p; - int ret = 0; + int status; if (netif_running(ndev)) return -EBUSY; @@ -3518,15 +3533,17 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p) return -EADDRNOTAVAIL; memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); + status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK); + if (status) + return status; spin_lock(&qdev->hw_lock); - if (ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr, - MAC_ADDR_TYPE_CAM_MAC, qdev->func)) {/* Unicast */ - QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n"); - ret = -1; - } + status = ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr, + MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ); spin_unlock(&qdev->hw_lock); - - return ret; + if (status) + QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n"); + ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK); + return status; } static void qlge_tx_timeout(struct net_device *ndev) -- cgit v1.2.3-70-g09d2 From 8587ea35ca6b4add4353b8a18b67d358aed0389e Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 23 Feb 2009 10:42:15 +0000 Subject: qlge: Change frame route hw semaphore granularity. Instead of taking/giving the hw semaphore repeatedly when iterating over several frame to queue route settings, we have the caller hold it until all are done. This reduces PCI bus chatter and possible waits. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index d316e508d06..16c056a62fc 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -418,10 +418,6 @@ int ql_get_routing_reg(struct ql_adapter *qdev, u32 index, u32 *value) { int status = 0; - status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); - if (status) - goto exit; - status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MW, 0); if (status) goto exit; @@ -433,7 +429,6 @@ int ql_get_routing_reg(struct ql_adapter *qdev, u32 index, u32 *value) goto exit; *value = ql_read32(qdev, RT_DATA); exit: - ql_sem_unlock(qdev, SEM_RT_IDX_MASK); return status; } @@ -445,13 +440,9 @@ exit: static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask, int enable) { - int status; + int status = -EINVAL; /* Return error if no mask match. */ u32 value = 0; - status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); - if (status) - return status; - QPRINTK(qdev, IFUP, DEBUG, "%s %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s mask %s the routing reg.\n", (enable ? "Adding" : "Removing"), @@ -547,7 +538,6 @@ static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask, ql_write32(qdev, RT_DATA, enable ? mask : 0); } exit: - ql_sem_unlock(qdev, SEM_RT_IDX_MASK); return status; } @@ -2916,13 +2906,17 @@ static int ql_route_initialize(struct ql_adapter *qdev) int status = 0; int i; + status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK); + if (status) + return status; + /* Clear all the entries in the routing table. */ for (i = 0; i < 16; i++) { status = ql_set_routing_reg(qdev, i, 0, 0); if (status) { QPRINTK(qdev, IFUP, ERR, "Failed to init routing register for CAM packets.\n"); - return status; + goto exit; } } @@ -2930,13 +2924,13 @@ static int ql_route_initialize(struct ql_adapter *qdev) if (status) { QPRINTK(qdev, IFUP, ERR, "Failed to init routing register for error packets.\n"); - return status; + goto exit; } status = ql_set_routing_reg(qdev, RT_IDX_BCAST_SLOT, RT_IDX_BCAST, 1); if (status) { QPRINTK(qdev, IFUP, ERR, "Failed to init routing register for broadcast packets.\n"); - return status; + goto exit; } /* If we have more than one inbound queue, then turn on RSS in the * routing block. @@ -2947,17 +2941,17 @@ static int ql_route_initialize(struct ql_adapter *qdev) if (status) { QPRINTK(qdev, IFUP, ERR, "Failed to init routing register for MATCH RSS packets.\n"); - return status; + goto exit; } } status = ql_set_routing_reg(qdev, RT_IDX_CAM_HIT_SLOT, RT_IDX_CAM_HIT, 1); - if (status) { + if (status) QPRINTK(qdev, IFUP, ERR, "Failed to init routing register for CAM packets.\n"); - return status; - } +exit: + ql_sem_unlock(qdev, SEM_RT_IDX_MASK); return status; } @@ -3518,6 +3512,7 @@ static void qlge_set_multicast_list(struct net_device *ndev) } exit: spin_unlock(&qdev->hw_lock); + ql_sem_unlock(qdev, SEM_RT_IDX_MASK); } static int qlge_set_mac_address(struct net_device *ndev, void *p) -- cgit v1.2.3-70-g09d2 From 49f2186d36a88ae6f7dd8261aff2cf80409af28d Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 23 Feb 2009 10:42:16 +0000 Subject: qlge: Optimize rx buffer refill process. RX Buffers are refilled in chunks of 16 at a time before notifying the hardware with a register write. This can cause several writes to take place in a given napi poll call. This change causes the write to take place only once at the end of the call. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 16c056a62fc..17198459918 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -863,7 +863,8 @@ static void ql_write_cq_idx(struct rx_ring *rx_ring) /* Process (refill) a large buffer queue. */ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) { - int clean_idx = rx_ring->lbq_clean_idx; + u32 clean_idx = rx_ring->lbq_clean_idx; + u32 start_idx = clean_idx; struct bq_desc *lbq_desc; u64 map; int i; @@ -910,19 +911,23 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) rx_ring->lbq_prod_idx += 16; if (rx_ring->lbq_prod_idx == rx_ring->lbq_len) rx_ring->lbq_prod_idx = 0; + rx_ring->lbq_free_cnt -= 16; + } + + if (start_idx != clean_idx) { QPRINTK(qdev, RX_STATUS, DEBUG, "lbq: updating prod idx = %d.\n", rx_ring->lbq_prod_idx); ql_write_db_reg(rx_ring->lbq_prod_idx, rx_ring->lbq_prod_idx_db_reg); - rx_ring->lbq_free_cnt -= 16; } } /* Process (refill) a small buffer queue. */ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) { - int clean_idx = rx_ring->sbq_clean_idx; + u32 clean_idx = rx_ring->sbq_clean_idx; + u32 start_idx = clean_idx; struct bq_desc *sbq_desc; u64 map; int i; @@ -972,13 +977,15 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring) rx_ring->sbq_prod_idx += 16; if (rx_ring->sbq_prod_idx == rx_ring->sbq_len) rx_ring->sbq_prod_idx = 0; + rx_ring->sbq_free_cnt -= 16; + } + + if (start_idx != clean_idx) { QPRINTK(qdev, RX_STATUS, DEBUG, "sbq: updating prod idx = %d.\n", rx_ring->sbq_prod_idx); ql_write_db_reg(rx_ring->sbq_prod_idx, rx_ring->sbq_prod_idx_db_reg); - - rx_ring->sbq_free_cnt -= 16; } } -- cgit v1.2.3-70-g09d2 From 4545a3f2765bb7d2d93468a8ffa578ac87a2c5c7 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 23 Feb 2009 10:42:17 +0000 Subject: qlge: Use one path to (re)fill rx buffers. Currently there are two paths for filling rx buffer queues. One is used during initialization and the other during runtime. This patch removes ql_alloc_sbq_buffers() and ql_alloc_lbq_buffers() and replaces them with a call to the runtime functions ql_update_lbq() and ql_update_sbq(). Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 170 +++++++++++++++---------------------------- 1 file changed, 59 insertions(+), 111 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 17198459918..655f3c4322e 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2105,47 +2105,6 @@ static void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring } } -/* - * Allocate and map a page for each element of the lbq. - */ -static int ql_alloc_lbq_buffers(struct ql_adapter *qdev, - struct rx_ring *rx_ring) -{ - int i; - struct bq_desc *lbq_desc; - u64 map; - __le64 *bq = rx_ring->lbq_base; - - for (i = 0; i < rx_ring->lbq_len; i++) { - lbq_desc = &rx_ring->lbq[i]; - memset(lbq_desc, 0, sizeof(lbq_desc)); - lbq_desc->addr = bq; - lbq_desc->index = i; - lbq_desc->p.lbq_page = alloc_page(GFP_ATOMIC); - if (unlikely(!lbq_desc->p.lbq_page)) { - QPRINTK(qdev, IFUP, ERR, "failed alloc_page().\n"); - goto mem_error; - } else { - map = pci_map_page(qdev->pdev, - lbq_desc->p.lbq_page, - 0, PAGE_SIZE, PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(qdev->pdev, map)) { - QPRINTK(qdev, IFUP, ERR, - "PCI mapping failed.\n"); - goto mem_error; - } - pci_unmap_addr_set(lbq_desc, mapaddr, map); - pci_unmap_len_set(lbq_desc, maplen, PAGE_SIZE); - *lbq_desc->addr = cpu_to_le64(map); - } - bq++; - } - return 0; -mem_error: - ql_free_lbq_buffers(qdev, rx_ring); - return -ENOMEM; -} - static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) { int i; @@ -2168,63 +2127,72 @@ static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring } } -/* Allocate and map an skb for each element of the sbq. */ -static int ql_alloc_sbq_buffers(struct ql_adapter *qdev, +/* Free all large and small rx buffers associated + * with the completion queues for this device. + */ +static void ql_free_rx_buffers(struct ql_adapter *qdev) +{ + int i; + struct rx_ring *rx_ring; + + for (i = 0; i < qdev->rx_ring_count; i++) { + rx_ring = &qdev->rx_ring[i]; + if (rx_ring->lbq) + ql_free_lbq_buffers(qdev, rx_ring); + if (rx_ring->sbq) + ql_free_sbq_buffers(qdev, rx_ring); + } +} + +static void ql_alloc_rx_buffers(struct ql_adapter *qdev) +{ + struct rx_ring *rx_ring; + int i; + + for (i = 0; i < qdev->rx_ring_count; i++) { + rx_ring = &qdev->rx_ring[i]; + if (rx_ring->type != TX_Q) + ql_update_buffer_queues(qdev, rx_ring); + } +} + +static void ql_init_lbq_ring(struct ql_adapter *qdev, + struct rx_ring *rx_ring) +{ + int i; + struct bq_desc *lbq_desc; + __le64 *bq = rx_ring->lbq_base; + + memset(rx_ring->lbq, 0, rx_ring->lbq_len * sizeof(struct bq_desc)); + for (i = 0; i < rx_ring->lbq_len; i++) { + lbq_desc = &rx_ring->lbq[i]; + memset(lbq_desc, 0, sizeof(*lbq_desc)); + lbq_desc->index = i; + lbq_desc->addr = bq; + bq++; + } +} + +static void ql_init_sbq_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) { int i; struct bq_desc *sbq_desc; - struct sk_buff *skb; - u64 map; __le64 *bq = rx_ring->sbq_base; + memset(rx_ring->sbq, 0, rx_ring->sbq_len * sizeof(struct bq_desc)); for (i = 0; i < rx_ring->sbq_len; i++) { sbq_desc = &rx_ring->sbq[i]; - memset(sbq_desc, 0, sizeof(sbq_desc)); + memset(sbq_desc, 0, sizeof(*sbq_desc)); sbq_desc->index = i; sbq_desc->addr = bq; - skb = netdev_alloc_skb(qdev->ndev, rx_ring->sbq_buf_size); - if (unlikely(!skb)) { - /* Better luck next round */ - QPRINTK(qdev, IFUP, ERR, - "small buff alloc failed for %d bytes at index %d.\n", - rx_ring->sbq_buf_size, i); - goto mem_err; - } - skb_reserve(skb, QLGE_SB_PAD); - sbq_desc->p.skb = skb; - /* - * Map only half the buffer. Because the - * other half may get some data copied to it - * when the completion arrives. - */ - map = pci_map_single(qdev->pdev, - skb->data, - rx_ring->sbq_buf_size / 2, - PCI_DMA_FROMDEVICE); - if (pci_dma_mapping_error(qdev->pdev, map)) { - QPRINTK(qdev, IFUP, ERR, "PCI mapping failed.\n"); - goto mem_err; - } - pci_unmap_addr_set(sbq_desc, mapaddr, map); - pci_unmap_len_set(sbq_desc, maplen, rx_ring->sbq_buf_size / 2); - *sbq_desc->addr = cpu_to_le64(map); bq++; } - return 0; -mem_err: - ql_free_sbq_buffers(qdev, rx_ring); - return -ENOMEM; } static void ql_free_rx_resources(struct ql_adapter *qdev, struct rx_ring *rx_ring) { - if (rx_ring->sbq_len) - ql_free_sbq_buffers(qdev, rx_ring); - if (rx_ring->lbq_len) - ql_free_lbq_buffers(qdev, rx_ring); - /* Free the small buffer queue. */ if (rx_ring->sbq_base) { pci_free_consistent(qdev->pdev, @@ -2302,11 +2270,7 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev, goto err_mem; } - if (ql_alloc_sbq_buffers(qdev, rx_ring)) { - QPRINTK(qdev, IFUP, ERR, - "Small buffer allocation failed.\n"); - goto err_mem; - } + ql_init_sbq_ring(qdev, rx_ring); } if (rx_ring->lbq_len) { @@ -2334,14 +2298,7 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev, goto err_mem; } - /* - * Allocate the buffers. - */ - if (ql_alloc_lbq_buffers(qdev, rx_ring)) { - QPRINTK(qdev, IFUP, ERR, - "Large buffer allocation failed.\n"); - goto err_mem; - } + ql_init_lbq_ring(qdev, rx_ring); } return 0; @@ -2489,10 +2446,10 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) bq_len = (rx_ring->lbq_len == 65536) ? 0 : (u16) rx_ring->lbq_len; cqicb->lbq_len = cpu_to_le16(bq_len); - rx_ring->lbq_prod_idx = rx_ring->lbq_len - 16; + rx_ring->lbq_prod_idx = 0; rx_ring->lbq_curr_idx = 0; - rx_ring->lbq_clean_idx = rx_ring->lbq_prod_idx; - rx_ring->lbq_free_cnt = 16; + rx_ring->lbq_clean_idx = 0; + rx_ring->lbq_free_cnt = rx_ring->lbq_len; } if (rx_ring->sbq_len) { cqicb->flags |= FLAGS_LS; /* Load sbq values */ @@ -2504,10 +2461,10 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) bq_len = (rx_ring->sbq_len == 65536) ? 0 : (u16) rx_ring->sbq_len; cqicb->sbq_len = cpu_to_le16(bq_len); - rx_ring->sbq_prod_idx = rx_ring->sbq_len - 16; + rx_ring->sbq_prod_idx = 0; rx_ring->sbq_curr_idx = 0; - rx_ring->sbq_clean_idx = rx_ring->sbq_prod_idx; - rx_ring->sbq_free_cnt = 16; + rx_ring->sbq_clean_idx = 0; + rx_ring->sbq_free_cnt = rx_ring->sbq_len; } switch (rx_ring->type) { case TX_Q: @@ -2560,17 +2517,6 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) QPRINTK(qdev, IFUP, ERR, "Failed to load CQICB.\n"); return err; } - QPRINTK(qdev, IFUP, INFO, "Successfully loaded CQICB.\n"); - /* - * Advance the producer index for the buffer queues. - */ - wmb(); - if (rx_ring->lbq_len) - ql_write_db_reg(rx_ring->lbq_prod_idx, - rx_ring->lbq_prod_idx_db_reg); - if (rx_ring->sbq_len) - ql_write_db_reg(rx_ring->sbq_prod_idx, - rx_ring->sbq_prod_idx_db_reg); return err; } @@ -3171,6 +3117,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) ql_tx_ring_clean(qdev); + ql_free_rx_buffers(qdev); spin_lock(&qdev->hw_lock); status = ql_adapter_reset(qdev); if (status) @@ -3193,6 +3140,7 @@ static int ql_adapter_up(struct ql_adapter *qdev) } spin_unlock(&qdev->hw_lock); set_bit(QL_ADAPTER_UP, &qdev->flags); + ql_alloc_rx_buffers(qdev); ql_enable_interrupts(qdev); ql_enable_all_completion_interrupts(qdev); if ((ql_read32(qdev, STS) & qdev->port_init)) { -- cgit v1.2.3-70-g09d2 From 125844eaff0e9600c92a753995564fd93c807f3c Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 26 Feb 2009 10:08:34 +0000 Subject: qlge: Move firmware event handler. This is not a logical change but rather a move of the inbound firmware event handler into it's own function as it will later be called by the outbound path. The addition of the mutex is to create exclusive access to the mailbox commands between inbound and outbound handling. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 1 + drivers/net/qlge/qlge_main.c | 1 + drivers/net/qlge/qlge_mpi.c | 88 ++++++++++++++++++++++++++++++-------------- 3 files changed, 62 insertions(+), 28 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 8b3c37afe80..2103fe6ff3a 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -1407,6 +1407,7 @@ struct ql_adapter { u32 mailbox_in; u32 mailbox_out; + struct mutex mpi_mutex; int tx_ring_size; int rx_ring_size; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 655f3c4322e..b144b6becfe 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3659,6 +3659,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev, INIT_DELAYED_WORK(&qdev->asic_reset_work, ql_asic_reset_work); INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work); INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work); + mutex_init(&qdev->mpi_mutex); if (!cards_found) { dev_info(&pdev->dev, "%s\n", DRV_STRING); diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index f9db78697e2..a4b810d0d3d 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -124,43 +124,75 @@ exit: ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); } +/* Process an async event and clear it unless it's an + * error condition. + * This can get called iteratively from the mpi_work thread + * when events arrive via an interrupt. + * It also gets called when a mailbox command is polling for + * it's completion. */ +static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) +{ + int status; + + /* Just get mailbox zero for now. */ + mbcp->out_count = 1; + status = ql_get_mb_sts(qdev, mbcp); + if (status) { + QPRINTK(qdev, DRV, ERR, + "Could not read MPI, resetting ASIC!\n"); + ql_queue_asic_error(qdev); + goto end; + } + + switch (mbcp->mbox_out[0]) { + + case AEN_LINK_UP: + ql_link_up(qdev, mbcp); + break; + + case AEN_LINK_DOWN: + ql_link_down(qdev, mbcp); + break; + + case AEN_FW_INIT_DONE: + ql_init_fw_done(qdev, mbcp); + break; + + case MB_CMD_STS_GOOD: + break; + + case AEN_FW_INIT_FAIL: + case AEN_SYS_ERR: + case MB_CMD_STS_ERR: + ql_queue_fw_error(qdev); + break; + + default: + QPRINTK(qdev, DRV, ERR, + "Unsupported AE %.08x.\n", mbcp->mbox_out[0]); + /* Clear the MPI firmware status. */ + } +end: + ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); + return status; +} + void ql_mpi_work(struct work_struct *work) { struct ql_adapter *qdev = container_of(work, struct ql_adapter, mpi_work.work); struct mbox_params mbc; struct mbox_params *mbcp = &mbc; - mbcp->out_count = 1; - while (ql_read32(qdev, STS) & STS_PI) { - if (ql_get_mb_sts(qdev, mbcp)) { - QPRINTK(qdev, DRV, ERR, - "Could not read MPI, resetting ASIC!\n"); - ql_queue_asic_error(qdev); - } + mutex_lock(&qdev->mpi_mutex); - switch (mbcp->mbox_out[0]) { - case AEN_LINK_UP: - ql_link_up(qdev, mbcp); - break; - case AEN_LINK_DOWN: - ql_link_down(qdev, mbcp); - break; - case AEN_FW_INIT_DONE: - ql_init_fw_done(qdev, mbcp); - break; - case MB_CMD_STS_GOOD: - break; - case AEN_FW_INIT_FAIL: - case AEN_SYS_ERR: - case MB_CMD_STS_ERR: - ql_queue_fw_error(qdev); - default: - /* Clear the MPI firmware status. */ - ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT); - break; - } + while (ql_read32(qdev, STS) & STS_PI) { + memset(mbcp, 0, sizeof(struct mbox_params)); + mbcp->out_count = 1; + ql_mpi_handler(qdev, mbcp); } + + mutex_unlock(&qdev->mpi_mutex); ql_enable_completion_interrupt(qdev, 0); } -- cgit v1.2.3-70-g09d2 From b0c2aadfa4d2194615ba8f5630be7ae686b9ed01 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 26 Feb 2009 10:08:35 +0000 Subject: qlge: Prepare to add new device. This organizes a few calls into a function table to enable adding new devices. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 17 ++++++++-- drivers/net/qlge/qlge_main.c | 80 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 78 insertions(+), 19 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 2103fe6ff3a..7bf18c6d7bc 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -28,7 +28,7 @@ } while (0) #define QLGE_VENDOR_ID 0x1077 -#define QLGE_DEVICE_ID 0x8012 +#define QLGE_DEVICE_ID_8012 0x8012 #define MAX_CPUS 8 #define MAX_TX_RINGS MAX_CPUS @@ -798,7 +798,7 @@ struct mbox_params { int out_count; }; -struct flash_params { +struct flash_params_8012 { u8 dev_id_str[4]; __le16 size; __le16 csum; @@ -808,6 +808,9 @@ struct flash_params { __le16 res; }; +union flash_params { + struct flash_params_8012 flash_params_8012; +}; /* * doorbell space for the rx ring context @@ -1367,6 +1370,12 @@ enum { CFG_DEFAULT_MAX_FRAME_SIZE = 0x00002580, }; +struct nic_operations { + + int (*get_flash) (struct ql_adapter *); + int (*port_initialize) (struct ql_adapter *); +}; + /* * The main Adapter structure definition. * This structure has all fields relevant to the hardware. @@ -1444,7 +1453,7 @@ struct ql_adapter { u32 port_init; u32 link_status; - struct flash_params flash; + union flash_params flash; struct net_device_stats stats; struct workqueue_struct *q_workqueue; @@ -1452,6 +1461,8 @@ struct ql_adapter { struct delayed_work asic_reset_work; struct delayed_work mpi_reset_work; struct delayed_work mpi_work; + struct nic_operations *nic_ops; + u16 device_id; }; /* diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index b144b6becfe..d1d8f05d5a1 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -75,7 +75,7 @@ module_param(irq_type, int, MSIX_IRQ); MODULE_PARM_DESC(irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy."); static struct pci_device_id qlge_pci_tbl[] __devinitdata = { - {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID)}, + {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)}, /* required last entry */ {0,} }; @@ -623,6 +623,28 @@ static void ql_enable_all_completion_interrupts(struct ql_adapter *qdev) } +static int ql_validate_flash(struct ql_adapter *qdev, u32 size, const char *str) +{ + int status, i; + u16 csum = 0; + __le16 *flash = (__le16 *)&qdev->flash; + + status = strncmp((char *)&qdev->flash, str, 4); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Invalid flash signature.\n"); + return status; + } + + for (i = 0; i < size; i++) + csum += le16_to_cpu(*flash++); + + if (csum) + QPRINTK(qdev, IFUP, ERR, + "Invalid flash checksum, csum = 0x%.04x.\n", csum); + + return csum; +} + static int ql_read_flash_word(struct ql_adapter *qdev, int offset, __le32 *data) { int status = 0; @@ -647,23 +669,24 @@ exit: return status; } -static int ql_get_flash_params(struct ql_adapter *qdev) +static int ql_get_8012_flash_params(struct ql_adapter *qdev) { int i; int status; __le32 *p = (__le32 *)&qdev->flash; u32 offset = 0; + u32 size = sizeof(struct flash_params_8012) / sizeof(u32); /* Second function's parameters follow the first * function's. */ if (qdev->func) - offset = sizeof(qdev->flash) / sizeof(u32); + offset = size; if (ql_sem_spinlock(qdev, SEM_FLASH_MASK)) return -ETIMEDOUT; - for (i = 0; i < sizeof(qdev->flash) / sizeof(u32); i++, p++) { + for (i = 0; i < size; i++, p++) { status = ql_read_flash_word(qdev, i+offset, p); if (status) { QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n"); @@ -671,6 +694,25 @@ static int ql_get_flash_params(struct ql_adapter *qdev) } } + + status = ql_validate_flash(qdev, + sizeof(struct flash_params_8012) / sizeof(u16), + "8012"); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Invalid flash.\n"); + status = -EINVAL; + goto exit; + } + + if (!is_valid_ether_addr(qdev->flash.flash_params_8012.mac_addr)) { + status = -EINVAL; + goto exit; + } + + memcpy(qdev->ndev->dev_addr, + qdev->flash.flash_params_8012.mac_addr, + qdev->ndev->addr_len); + exit: ql_sem_unlock(qdev, SEM_FLASH_MASK); return status; @@ -747,7 +789,7 @@ exit: * This functionality may be done in the MPI firmware at a * later date. */ -static int ql_port_initialize(struct ql_adapter *qdev) +static int ql_8012_port_initialize(struct ql_adapter *qdev) { int status = 0; u32 data; @@ -2994,11 +3036,12 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) } } - status = ql_port_initialize(qdev); - if (status) { - QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n"); - return status; - } + /* Initialize the port and set the max framesize. */ + status = qdev->nic_ops->port_initialize(qdev); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n"); + return status; + } /* Set up the MAC address and frame routing filter. */ status = ql_cam_route_initialize(qdev); @@ -3509,6 +3552,12 @@ static void ql_asic_reset_work(struct work_struct *work) ql_cycle_adapter(qdev); } +static struct nic_operations qla8012_nic_ops = { + .get_flash = ql_get_8012_flash_params, + .port_initialize = ql_8012_port_initialize, +}; + + static void ql_get_board_info(struct ql_adapter *qdev) { qdev->func = @@ -3527,6 +3576,9 @@ static void ql_get_board_info(struct ql_adapter *qdev) qdev->mailbox_out = PROC_ADDR_MPI_RISC | PROC_ADDR_FUNC0_MBO; } qdev->chip_rev_id = ql_read32(qdev, REV_ID); + qdev->device_id = qdev->pdev->device; + if (qdev->device_id == QLGE_DEVICE_ID_8012) + qdev->nic_ops = &qla8012_nic_ops; } static void ql_release_all(struct pci_dev *pdev) @@ -3619,24 +3671,20 @@ static int __devinit ql_init_device(struct pci_dev *pdev, goto err_out; } - ql_get_board_info(qdev); qdev->ndev = ndev; qdev->pdev = pdev; + ql_get_board_info(qdev); qdev->msg_enable = netif_msg_init(debug, default_msg); spin_lock_init(&qdev->hw_lock); spin_lock_init(&qdev->stats_lock); /* make sure the EEPROM is good */ - err = ql_get_flash_params(qdev); + err = qdev->nic_ops->get_flash(qdev); if (err) { dev_err(&pdev->dev, "Invalid FLASH.\n"); goto err_out; } - if (!is_valid_ether_addr(qdev->flash.mac_addr)) - goto err_out; - - memcpy(ndev->dev_addr, qdev->flash.mac_addr, ndev->addr_len); memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len); /* Set up the default ring sizes. */ -- cgit v1.2.3-70-g09d2 From 4974097a97c6c11c22c2242f70821e2af65ef8e7 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Thu, 26 Feb 2009 10:08:36 +0000 Subject: qlge: Reduce debug print output. Get rid of some noise that is for debug only. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index d1d8f05d5a1..b4c6fd7a761 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -58,8 +58,8 @@ static const u32 default_msg = NETIF_MSG_IFUP | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR | - NETIF_MSG_TX_QUEUED | - NETIF_MSG_INTR | NETIF_MSG_TX_DONE | NETIF_MSG_RX_STATUS | +/* NETIF_MSG_TX_QUEUED | */ +/* NETIF_MSG_INTR | NETIF_MSG_TX_DONE | NETIF_MSG_RX_STATUS | */ /* NETIF_MSG_PKTDATA | */ NETIF_MSG_HW | NETIF_MSG_WOL | 0; @@ -327,7 +327,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | (addr[5]); - QPRINTK(qdev, IFUP, INFO, + QPRINTK(qdev, IFUP, DEBUG, "Adding %s address %pM" " at index %d in the CAM.\n", ((type == @@ -2552,7 +2552,7 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) QPRINTK(qdev, IFUP, DEBUG, "Invalid rx_ring->type = %d.\n", rx_ring->type); } - QPRINTK(qdev, IFUP, INFO, "Initializing rx work queue.\n"); + QPRINTK(qdev, IFUP, DEBUG, "Initializing rx work queue.\n"); err = ql_write_cfg(qdev, cqicb, sizeof(struct cqicb), CFG_LCQ, rx_ring->cq_id); if (err) { @@ -2605,7 +2605,7 @@ static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring) QPRINTK(qdev, IFUP, ERR, "Failed to load tx_ring.\n"); return err; } - QPRINTK(qdev, IFUP, INFO, "Successfully loaded WQICB.\n"); + QPRINTK(qdev, IFUP, DEBUG, "Successfully loaded WQICB.\n"); return err; } @@ -2647,7 +2647,7 @@ static void ql_enable_msix(struct ql_adapter *qdev) (qdev->pdev, qdev->msi_x_entry, qdev->rx_ring_count)) { set_bit(QL_MSIX_ENABLED, &qdev->flags); qdev->intr_count = qdev->rx_ring_count; - QPRINTK(qdev, IFUP, INFO, + QPRINTK(qdev, IFUP, DEBUG, "MSI-X Enabled, got %d vectors.\n", qdev->intr_count); return; @@ -2774,11 +2774,11 @@ static void ql_free_irq(struct ql_adapter *qdev) if (test_bit(QL_MSIX_ENABLED, &qdev->flags)) { free_irq(qdev->msi_x_entry[i].vector, &qdev->rx_ring[i]); - QPRINTK(qdev, IFDOWN, ERR, + QPRINTK(qdev, IFDOWN, DEBUG, "freeing msix interrupt %d.\n", i); } else { free_irq(qdev->pdev->irq, &qdev->rx_ring[0]); - QPRINTK(qdev, IFDOWN, ERR, + QPRINTK(qdev, IFDOWN, DEBUG, "freeing msi interrupt %d.\n", i); } } @@ -2809,7 +2809,7 @@ static int ql_request_irq(struct ql_adapter *qdev) i); goto err_irq; } else { - QPRINTK(qdev, IFUP, INFO, + QPRINTK(qdev, IFUP, DEBUG, "Hooked intr %d, queue type %s%s%s, with name %s.\n", i, qdev->rx_ring[i].type == @@ -2884,14 +2884,14 @@ static int ql_start_rss(struct ql_adapter *qdev) get_random_bytes((void *)&ricb->ipv6_hash_key[0], 40); get_random_bytes((void *)&ricb->ipv4_hash_key[0], 16); - QPRINTK(qdev, IFUP, INFO, "Initializing RSS.\n"); + QPRINTK(qdev, IFUP, DEBUG, "Initializing RSS.\n"); status = ql_write_cfg(qdev, ricb, sizeof(ricb), CFG_LR, 0); if (status) { QPRINTK(qdev, IFUP, ERR, "Failed to load RICB.\n"); return status; } - QPRINTK(qdev, IFUP, INFO, "Successfully loaded RICB.\n"); + QPRINTK(qdev, IFUP, DEBUG, "Successfully loaded RICB.\n"); return status; } @@ -3053,7 +3053,7 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) /* Start NAPI for the RSS queues. */ for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) { - QPRINTK(qdev, IFUP, INFO, "Enabling NAPI for rx_ring[%d].\n", + QPRINTK(qdev, IFUP, DEBUG, "Enabling NAPI for rx_ring[%d].\n", i); napi_enable(&qdev->rx_ring[i].napi); } -- cgit v1.2.3-70-g09d2 From cdca8d02ea4229c2ccf3c27fb537b150843f67c9 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 2 Mar 2009 08:07:31 +0000 Subject: qlge: Add support for device ID 8000. This device has more firmware support for link management, setting TX and RX maximum frame sizes. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 37 ++++++++++++++++++++++++- drivers/net/qlge/qlge_main.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 7bf18c6d7bc..5f60ec4efb3 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -29,7 +29,7 @@ #define QLGE_VENDOR_ID 0x1077 #define QLGE_DEVICE_ID_8012 0x8012 - +#define QLGE_DEVICE_ID_8000 0x8000 #define MAX_CPUS 8 #define MAX_TX_RINGS MAX_CPUS #define MAX_RX_RINGS ((MAX_CPUS * 2) + 1) @@ -808,8 +808,42 @@ struct flash_params_8012 { __le16 res; }; +/* 8000 device's flash is a different structure + * at a different offset in flash. + */ +#define FUNC0_FLASH_OFFSET 0x140200 +#define FUNC1_FLASH_OFFSET 0x140600 + +/* Flash related data structures. */ +struct flash_params_8000 { + u8 dev_id_str[4]; /* "8000" */ + __le16 ver; + __le16 size; + __le16 csum; + __le16 reserved0; + __le16 total_size; + __le16 entry_count; + u8 data_type0; + u8 data_size0; + u8 mac_addr[6]; + u8 data_type1; + u8 data_size1; + u8 mac_addr1[6]; + u8 data_type2; + u8 data_size2; + __le16 vlan_id; + u8 data_type3; + u8 data_size3; + __le16 last; + u8 reserved1[464]; + __le16 subsys_ven_id; + __le16 subsys_dev_id; + u8 reserved2[4]; +}; + union flash_params { struct flash_params_8012 flash_params_8012; + struct flash_params_8000 flash_params_8000; }; /* @@ -1535,6 +1569,7 @@ void ql_queue_asic_error(struct ql_adapter *qdev); u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr); void ql_set_ethtool_ops(struct net_device *ndev); int ql_read_xgmac_reg64(struct ql_adapter *qdev, u32 reg, u64 *data); +int ql_mb_get_fw_state(struct ql_adapter *qdev); #if 1 #define QL_ALL_DUMP diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index b4c6fd7a761..29334d99b43 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -76,6 +76,7 @@ MODULE_PARM_DESC(irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy."); static struct pci_device_id qlge_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)}, + {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)}, /* required last entry */ {0,} }; @@ -669,6 +670,57 @@ exit: return status; } +static int ql_get_8000_flash_params(struct ql_adapter *qdev) +{ + u32 i, size; + int status; + __le32 *p = (__le32 *)&qdev->flash; + u32 offset; + + /* Get flash offset for function and adjust + * for dword access. + */ + if (!qdev->func) + offset = FUNC0_FLASH_OFFSET / sizeof(u32); + else + offset = FUNC1_FLASH_OFFSET / sizeof(u32); + + if (ql_sem_spinlock(qdev, SEM_FLASH_MASK)) + return -ETIMEDOUT; + + size = sizeof(struct flash_params_8000) / sizeof(u32); + for (i = 0; i < size; i++, p++) { + status = ql_read_flash_word(qdev, i+offset, p); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n"); + goto exit; + } + } + + status = ql_validate_flash(qdev, + sizeof(struct flash_params_8000) / sizeof(u16), + "8000"); + if (status) { + QPRINTK(qdev, IFUP, ERR, "Invalid flash.\n"); + status = -EINVAL; + goto exit; + } + + if (!is_valid_ether_addr(qdev->flash.flash_params_8000.mac_addr)) { + QPRINTK(qdev, IFUP, ERR, "Invalid MAC address.\n"); + status = -EINVAL; + goto exit; + } + + memcpy(qdev->ndev->dev_addr, + qdev->flash.flash_params_8000.mac_addr, + qdev->ndev->addr_len); + +exit: + ql_sem_unlock(qdev, SEM_FLASH_MASK); + return status; +} + static int ql_get_8012_flash_params(struct ql_adapter *qdev) { int i; @@ -783,6 +835,11 @@ exit: return status; } +static int ql_8000_port_initialize(struct ql_adapter *qdev) +{ + return ql_mb_get_fw_state(qdev); +} + /* Take the MAC Core out of reset. * Enable statistics counting. * Take the transmitter/receiver out of reset. @@ -3557,6 +3614,11 @@ static struct nic_operations qla8012_nic_ops = { .port_initialize = ql_8012_port_initialize, }; +static struct nic_operations qla8000_nic_ops = { + .get_flash = ql_get_8000_flash_params, + .port_initialize = ql_8000_port_initialize, +}; + static void ql_get_board_info(struct ql_adapter *qdev) { @@ -3579,6 +3641,8 @@ static void ql_get_board_info(struct ql_adapter *qdev) qdev->device_id = qdev->pdev->device; if (qdev->device_id == QLGE_DEVICE_ID_8012) qdev->nic_ops = &qla8012_nic_ops; + else if (qdev->device_id == QLGE_DEVICE_ID_8000) + qdev->nic_ops = &qla8000_nic_ops; } static void ql_release_all(struct pci_dev *pdev) -- cgit v1.2.3-70-g09d2 From bcc2cb3b97e37317c301309d7052bb61e6cce2c4 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 2 Mar 2009 08:07:32 +0000 Subject: qlge: Add support for getting/setting port config. This patch adds functionality to get and set port parameters. Currently it is used to set maximum TX/RX frame sizes. This process is also capable of setting: 1) Pause type: Standard or Priority based. 2) Loop back mode. 3) Enable Jumbo frame mode (included here...) Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 6 ++ drivers/net/qlge/qlge_main.c | 14 ++- drivers/net/qlge/qlge_mpi.c | 209 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 228 insertions(+), 1 deletion(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 5f60ec4efb3..6f9fd24bf38 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -1450,6 +1450,7 @@ struct ql_adapter { u32 mailbox_in; u32 mailbox_out; + struct mbox_params idc_mbc; struct mutex mpi_mutex; int tx_ring_size; @@ -1486,6 +1487,8 @@ struct ql_adapter { u32 port_link_up; u32 port_init; u32 link_status; + u32 link_config; + u32 max_frame_size; union flash_params flash; @@ -1495,6 +1498,8 @@ struct ql_adapter { struct delayed_work asic_reset_work; struct delayed_work mpi_reset_work; struct delayed_work mpi_work; + struct delayed_work mpi_port_cfg_work; + struct completion ide_completion; struct nic_operations *nic_ops; u16 device_id; }; @@ -1569,6 +1574,7 @@ void ql_queue_asic_error(struct ql_adapter *qdev); u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr); void ql_set_ethtool_ops(struct net_device *ndev); int ql_read_xgmac_reg64(struct ql_adapter *qdev, u32 reg, u64 *data); +void ql_mpi_port_cfg_work(struct work_struct *work); int ql_mb_get_fw_state(struct ql_adapter *qdev); #if 1 diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 29334d99b43..7c1ce576575 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -837,7 +837,14 @@ exit: static int ql_8000_port_initialize(struct ql_adapter *qdev) { - return ql_mb_get_fw_state(qdev); + int status; + status = ql_mb_get_fw_state(qdev); + if (status) + goto exit; + /* Wake up a worker to get/set the TX/RX frame sizes. */ + queue_delayed_work(qdev->workqueue, &qdev->mpi_port_cfg_work, 0); +exit: + return status; } /* Take the MAC Core out of reset. @@ -3188,6 +3195,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) cancel_delayed_work_sync(&qdev->asic_reset_work); cancel_delayed_work_sync(&qdev->mpi_reset_work); cancel_delayed_work_sync(&qdev->mpi_work); + cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); /* The default queue at index 0 is always processed in * a workqueue. @@ -3462,6 +3470,8 @@ static int qlge_change_mtu(struct net_device *ndev, int new_mtu) if (ndev->mtu == 1500 && new_mtu == 9000) { QPRINTK(qdev, IFUP, ERR, "Changing to jumbo MTU.\n"); + queue_delayed_work(qdev->workqueue, + &qdev->mpi_port_cfg_work, 0); } else if (ndev->mtu == 9000 && new_mtu == 1500) { QPRINTK(qdev, IFUP, ERR, "Changing to normal MTU.\n"); } else if ((ndev->mtu == 1500 && new_mtu == 1500) || @@ -3771,7 +3781,9 @@ static int __devinit ql_init_device(struct pci_dev *pdev, INIT_DELAYED_WORK(&qdev->asic_reset_work, ql_asic_reset_work); INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work); INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work); + INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work); mutex_init(&qdev->mpi_mutex); + init_completion(&qdev->ide_completion); if (!cards_found) { dev_info(&pdev->dev, "%s\n", DRV_STRING); diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 11102bec36b..ef610c674df 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -138,6 +138,27 @@ end: return status; } +/* Process an inter-device event completion. + * If good, signal the caller's completion. + */ +static int ql_idc_cmplt_aen(struct ql_adapter *qdev) +{ + int status; + struct mbox_params *mbcp = &qdev->idc_mbc; + mbcp->out_count = 4; + status = ql_get_mb_sts(qdev, mbcp); + if (status) { + QPRINTK(qdev, DRV, ERR, + "Could not read MPI, resetting RISC!\n"); + ql_queue_fw_error(qdev); + } else + /* Wake up the sleeping mpi_idc_work thread that is + * waiting for this event. + */ + complete(&qdev->ide_completion); + + return status; +} static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp) { mbcp->out_count = 2; @@ -241,6 +262,16 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) status = ql_get_mb_sts(qdev, mbcp); return status; + /* Process and inbound IDC event. + * This will happen when we're trying to + * change tx/rx max frame size, change pause + * paramters or loopback mode. + */ + case AEN_IDC_CMPLT: + case AEN_IDC_EXT: + status = ql_idc_cmplt_aen(qdev); + break; + case AEN_LINK_UP: ql_link_up(qdev, mbcp); break; @@ -391,6 +422,182 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev) return status; } +/* Get link settings and maximum frame size settings + * for the current port. + * Most likely will block. + */ +static int ql_mb_set_port_cfg(struct ql_adapter *qdev) +{ + struct mbox_params mbc; + struct mbox_params *mbcp = &mbc; + int status = 0; + + memset(mbcp, 0, sizeof(struct mbox_params)); + + mbcp->in_count = 3; + mbcp->out_count = 1; + + mbcp->mbox_in[0] = MB_CMD_SET_PORT_CFG; + mbcp->mbox_in[1] = qdev->link_config; + mbcp->mbox_in[2] = qdev->max_frame_size; + + + status = ql_mailbox_command(qdev, mbcp); + if (status) + return status; + + if (mbcp->mbox_out[0] == MB_CMD_STS_INTRMDT) { + QPRINTK(qdev, DRV, ERR, + "Port Config sent, wait for IDC.\n"); + } else if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { + QPRINTK(qdev, DRV, ERR, + "Failed Set Port Configuration.\n"); + status = -EIO; + } + return status; +} + +/* Get link settings and maximum frame size settings + * for the current port. + * Most likely will block. + */ +static int ql_mb_get_port_cfg(struct ql_adapter *qdev) +{ + struct mbox_params mbc; + struct mbox_params *mbcp = &mbc; + int status = 0; + + memset(mbcp, 0, sizeof(struct mbox_params)); + + mbcp->in_count = 1; + mbcp->out_count = 3; + + mbcp->mbox_in[0] = MB_CMD_GET_PORT_CFG; + + status = ql_mailbox_command(qdev, mbcp); + if (status) + return status; + + if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { + QPRINTK(qdev, DRV, ERR, + "Failed Get Port Configuration.\n"); + status = -EIO; + } else { + QPRINTK(qdev, DRV, DEBUG, + "Passed Get Port Configuration.\n"); + qdev->link_config = mbcp->mbox_out[1]; + qdev->max_frame_size = mbcp->mbox_out[2]; + } + return status; +} + +/* IDC - Inter Device Communication... + * Some firmware commands require consent of adjacent FCOE + * function. This function waits for the OK, or a + * counter-request for a little more time.i + * The firmware will complete the request if the other + * function doesn't respond. + */ +static int ql_idc_wait(struct ql_adapter *qdev) +{ + int status = -ETIMEDOUT; + long wait_time = 1 * HZ; + struct mbox_params *mbcp = &qdev->idc_mbc; + do { + /* Wait here for the command to complete + * via the IDC process. + */ + wait_time = + wait_for_completion_timeout(&qdev->ide_completion, + wait_time); + if (!wait_time) { + QPRINTK(qdev, DRV, ERR, + "IDC Timeout.\n"); + break; + } + /* Now examine the response from the IDC process. + * We might have a good completion or a request for + * more wait time. + */ + if (mbcp->mbox_out[0] == AEN_IDC_EXT) { + QPRINTK(qdev, DRV, ERR, + "IDC Time Extension from function.\n"); + wait_time += (mbcp->mbox_out[1] >> 8) & 0x0000000f; + } else if (mbcp->mbox_out[0] == AEN_IDC_CMPLT) { + QPRINTK(qdev, DRV, ERR, + "IDC Success.\n"); + status = 0; + break; + } else { + QPRINTK(qdev, DRV, ERR, + "IDC: Invalid State 0x%.04x.\n", + mbcp->mbox_out[0]); + status = -EIO; + break; + } + } while (wait_time); + + return status; +} + +/* API called in work thread context to set new TX/RX + * maximum frame size values to match MTU. + */ +static int ql_set_port_cfg(struct ql_adapter *qdev) +{ + int status; + status = ql_mb_set_port_cfg(qdev); + if (status) + return status; + status = ql_idc_wait(qdev); + return status; +} + +/* The following routines are worker threads that process + * events that may sleep waiting for completion. + */ + +/* This thread gets the maximum TX and RX frame size values + * from the firmware and, if necessary, changes them to match + * the MTU setting. + */ +void ql_mpi_port_cfg_work(struct work_struct *work) +{ + struct ql_adapter *qdev = + container_of(work, struct ql_adapter, mpi_port_cfg_work.work); + struct net_device *ndev = qdev->ndev; + int status; + + status = ql_mb_get_port_cfg(qdev); + if (status) { + QPRINTK(qdev, DRV, ERR, + "Bug: Failed to get port config data.\n"); + goto err; + } + + if (ndev->mtu <= 2500) + goto end; + else if (qdev->link_config & CFG_JUMBO_FRAME_SIZE && + qdev->max_frame_size == + CFG_DEFAULT_MAX_FRAME_SIZE) + goto end; + + qdev->link_config |= CFG_JUMBO_FRAME_SIZE; + qdev->max_frame_size = CFG_DEFAULT_MAX_FRAME_SIZE; + status = ql_set_port_cfg(qdev); + if (status) { + QPRINTK(qdev, DRV, ERR, + "Bug: Failed to set port config data.\n"); + goto err; + } +end: + clear_bit(QL_PORT_CFG, &qdev->flags); + return; +err: + ql_queue_fw_error(qdev); + goto end; +} + void ql_mpi_work(struct work_struct *work) { struct ql_adapter *qdev = @@ -414,5 +621,7 @@ void ql_mpi_reset_work(struct work_struct *work) { struct ql_adapter *qdev = container_of(work, struct ql_adapter, mpi_reset_work.work); + cancel_delayed_work_sync(&qdev->mpi_work); + cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); ql_soft_reset_mpi_risc(qdev); } -- cgit v1.2.3-70-g09d2 From 2ee1e272d1661d7846da753248a4141ad5f16d69 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Tue, 3 Mar 2009 12:10:33 +0000 Subject: qlge: Add worker-handler for firmware events. This worker and it's supporting routines are used for IDC 'inter-device-communication' events that require an ACK mailbox command be sent to allow completion of the request. These requests are originated by another function wanting to change some common port paramters. Typical example would be: 1) Change max TX/RX frame size allowed. 2) Change pause parameters. 3) Change loopback mode. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 3 + drivers/net/qlge/qlge_main.c | 4 +- drivers/net/qlge/qlge_mpi.c | 143 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 1 deletion(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 6f9fd24bf38..9918106f2a5 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -1499,6 +1499,7 @@ struct ql_adapter { struct delayed_work mpi_reset_work; struct delayed_work mpi_work; struct delayed_work mpi_port_cfg_work; + struct delayed_work mpi_idc_work; struct completion ide_completion; struct nic_operations *nic_ops; u16 device_id; @@ -1574,8 +1575,10 @@ void ql_queue_asic_error(struct ql_adapter *qdev); u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr); void ql_set_ethtool_ops(struct net_device *ndev); int ql_read_xgmac_reg64(struct ql_adapter *qdev, u32 reg, u64 *data); +void ql_mpi_idc_work(struct work_struct *work); void ql_mpi_port_cfg_work(struct work_struct *work); int ql_mb_get_fw_state(struct ql_adapter *qdev); +int ql_cam_route_initialize(struct ql_adapter *qdev); #if 1 #define QL_ALL_DUMP diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 7c1ce576575..d800ff40b32 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3014,7 +3014,7 @@ exit: return status; } -static int ql_cam_route_initialize(struct ql_adapter *qdev) +int ql_cam_route_initialize(struct ql_adapter *qdev) { int status; @@ -3195,6 +3195,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) cancel_delayed_work_sync(&qdev->asic_reset_work); cancel_delayed_work_sync(&qdev->mpi_reset_work); cancel_delayed_work_sync(&qdev->mpi_work); + cancel_delayed_work_sync(&qdev->mpi_idc_work); cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); /* The default queue at index 0 is always processed in @@ -3782,6 +3783,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev, INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work); INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work); INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work); + INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work); mutex_init(&qdev->mpi_mutex); init_completion(&qdev->ide_completion); diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 3b4b494387a..9f1fe542e27 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -138,6 +138,40 @@ end: return status; } +/* We are being asked by firmware to accept + * a change to the port. This is only + * a change to max frame sizes (Tx/Rx), pause + * paramters, or loopback mode. We wake up a worker + * to handler processing this since a mailbox command + * will need to be sent to ACK the request. + */ +static int ql_idc_req_aen(struct ql_adapter *qdev) +{ + int status; + struct mbox_params *mbcp = &qdev->idc_mbc; + + QPRINTK(qdev, DRV, ERR, "Enter!\n"); + /* Get the status data and start up a thread to + * handle the request. + */ + mbcp = &qdev->idc_mbc; + mbcp->out_count = 4; + status = ql_get_mb_sts(qdev, mbcp); + if (status) { + QPRINTK(qdev, DRV, ERR, + "Could not read MPI, resetting ASIC!\n"); + ql_queue_asic_error(qdev); + } else { + /* Begin polled mode early so + * we don't get another interrupt + * when we leave mpi_worker. + */ + ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16)); + queue_delayed_work(qdev->workqueue, &qdev->mpi_idc_work, 0); + } + return status; +} + /* Process an inter-device event completion. * If good, signal the caller's completion. */ @@ -175,6 +209,35 @@ static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp) qdev->link_status = mbcp->mbox_out[1]; QPRINTK(qdev, DRV, ERR, "Link Up.\n"); + /* If we're coming back from an IDC event + * then set up the CAM and frame routing. + */ + if (test_bit(QL_CAM_RT_SET, &qdev->flags)) { + status = ql_cam_route_initialize(qdev); + if (status) { + QPRINTK(qdev, IFUP, ERR, + "Failed to init CAM/Routing tables.\n"); + return; + } else + clear_bit(QL_CAM_RT_SET, &qdev->flags); + } + + /* Queue up a worker to check the frame + * size information, and fix it if it's not + * to our liking. + */ + if (!test_bit(QL_PORT_CFG, &qdev->flags)) { + QPRINTK(qdev, DRV, ERR, "Queue Port Config Worker!\n"); + set_bit(QL_PORT_CFG, &qdev->flags); + /* Begin polled mode early so + * we don't get another interrupt + * when we leave mpi_worker dpc. + */ + ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16)); + queue_delayed_work(qdev->workqueue, + &qdev->mpi_port_cfg_work, 0); + } + netif_carrier_on(qdev->ndev); } @@ -283,6 +346,15 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp) status = ql_get_mb_sts(qdev, mbcp); return status; + /* We are being asked by firmware to accept + * a change to the port. This is only + * a change to max frame sizes (Tx/Rx), pause + * paramters, or loopback mode. + */ + case AEN_IDC_REQ: + status = ql_idc_req_aen(qdev); + break; + /* Process and inbound IDC event. * This will happen when we're trying to * change tx/rx max frame size, change pause @@ -451,6 +523,38 @@ int ql_mb_get_fw_state(struct ql_adapter *qdev) return status; } +/* Send and ACK mailbox command to the firmware to + * let it continue with the change. + */ +int ql_mb_idc_ack(struct ql_adapter *qdev) +{ + struct mbox_params mbc; + struct mbox_params *mbcp = &mbc; + int status = 0; + + memset(mbcp, 0, sizeof(struct mbox_params)); + + mbcp->in_count = 5; + mbcp->out_count = 1; + + mbcp->mbox_in[0] = MB_CMD_IDC_ACK; + mbcp->mbox_in[1] = qdev->idc_mbc.mbox_out[1]; + mbcp->mbox_in[2] = qdev->idc_mbc.mbox_out[2]; + mbcp->mbox_in[3] = qdev->idc_mbc.mbox_out[3]; + mbcp->mbox_in[4] = qdev->idc_mbc.mbox_out[4]; + + status = ql_mailbox_command(qdev, mbcp); + if (status) + return status; + + if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { + QPRINTK(qdev, DRV, ERR, + "Failed IDC ACK send.\n"); + status = -EIO; + } + return status; +} + /* Get link settings and maximum frame size settings * for the current port. * Most likely will block. @@ -627,6 +731,44 @@ err: goto end; } +/* Process an inter-device request. This is issues by + * the firmware in response to another function requesting + * a change to the port. We set a flag to indicate a change + * has been made and then send a mailbox command ACKing + * the change request. + */ +void ql_mpi_idc_work(struct work_struct *work) +{ + struct ql_adapter *qdev = + container_of(work, struct ql_adapter, mpi_idc_work.work); + int status; + struct mbox_params *mbcp = &qdev->idc_mbc; + u32 aen; + + aen = mbcp->mbox_out[1] >> 16; + + switch (aen) { + default: + QPRINTK(qdev, DRV, ERR, + "Bug: Unhandled IDC action.\n"); + break; + case MB_CMD_PORT_RESET: + case MB_CMD_SET_PORT_CFG: + case MB_CMD_STOP_FW: + netif_carrier_off(qdev->ndev); + /* Signal the resulting link up AEN + * that the frame routing and mac addr + * needs to be set. + * */ + set_bit(QL_CAM_RT_SET, &qdev->flags); + status = ql_mb_idc_ack(qdev); + if (status) { + QPRINTK(qdev, DRV, ERR, + "Bug: No pending IDC!\n"); + } + } +} + void ql_mpi_work(struct work_struct *work) { struct ql_adapter *qdev = @@ -652,5 +794,6 @@ void ql_mpi_reset_work(struct work_struct *work) container_of(work, struct ql_adapter, mpi_reset_work.work); cancel_delayed_work_sync(&qdev->mpi_work); cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); + cancel_delayed_work_sync(&qdev->mpi_idc_work); ql_soft_reset_mpi_risc(qdev); } -- cgit v1.2.3-70-g09d2 From db98812f6bbe17c5994d6290a68f8de8aa5ff8b9 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 9 Mar 2009 10:59:17 +0000 Subject: qlge: Move reset logic into asic_reset_worker func. Get rid of extraneous ql_cycle_adapter. It's only called from the one place. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index d800ff40b32..ed7138d07ba 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3263,28 +3263,6 @@ err_init: return err; } -static int ql_cycle_adapter(struct ql_adapter *qdev) -{ - int status; - - status = ql_adapter_down(qdev); - if (status) - goto error; - - status = ql_adapter_up(qdev); - if (status) - goto error; - - return status; -error: - QPRINTK(qdev, IFUP, ALERT, - "Driver up/down cycle failed, closing device\n"); - rtnl_lock(); - dev_close(qdev->ndev); - rtnl_unlock(); - return status; -} - static void ql_release_adapter_resources(struct ql_adapter *qdev) { ql_free_mem_resources(qdev); @@ -3617,7 +3595,24 @@ static void ql_asic_reset_work(struct work_struct *work) { struct ql_adapter *qdev = container_of(work, struct ql_adapter, asic_reset_work.work); - ql_cycle_adapter(qdev); + int status; + + status = ql_adapter_down(qdev); + if (status) + goto error; + + status = ql_adapter_up(qdev); + if (status) + goto error; + + return; +error: + QPRINTK(qdev, IFUP, ALERT, + "Driver up/down cycle failed, closing device\n"); + rtnl_lock(); + set_bit(QL_ADAPTER_UP, &qdev->flags); + dev_close(qdev->ndev); + rtnl_unlock(); } static struct nic_operations qla8012_nic_ops = { -- cgit v1.2.3-70-g09d2 From a75ee7f1ccace560642e5dc6b1c0e22c73da5a8c Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 9 Mar 2009 10:59:18 +0000 Subject: qlge: Remove debug junk from asic reset logic. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index ed7138d07ba..bc04aebc928 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3129,36 +3129,23 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) static int ql_adapter_reset(struct ql_adapter *qdev) { u32 value; - int max_wait_time; int status = 0; - int resetCnt = 0; + unsigned long end_jiffies = jiffies + + max((unsigned long)1, usecs_to_jiffies(30)); -#define MAX_RESET_CNT 1 -issueReset: - resetCnt++; - QPRINTK(qdev, IFDOWN, DEBUG, "Issue soft reset to chip.\n"); ql_write32(qdev, RST_FO, (RST_FO_FR << 16) | RST_FO_FR); - /* Wait for reset to complete. */ - max_wait_time = 3; - QPRINTK(qdev, IFDOWN, DEBUG, "Wait %d seconds for reset to complete.\n", - max_wait_time); + do { value = ql_read32(qdev, RST_FO); if ((value & RST_FO_FR) == 0) break; + cpu_relax(); + } while (time_before(jiffies, end_jiffies)); - ssleep(1); - } while ((--max_wait_time)); if (value & RST_FO_FR) { - QPRINTK(qdev, IFDOWN, ERR, - "Stuck in SoftReset: FSC_SR:0x%08x\n", value); - if (resetCnt < MAX_RESET_CNT) - goto issueReset; - } - if (max_wait_time == 0) { - status = -ETIMEDOUT; QPRINTK(qdev, IFDOWN, ERR, "ETIMEOUT!!! errored out of resetting the chip!\n"); + status = -ETIMEDOUT; } return status; -- cgit v1.2.3-70-g09d2 From d555f5921f2b0d9f65b547dd0be67c870ff5a56f Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 9 Mar 2009 10:59:19 +0000 Subject: qlge: Increase filtering for inbound csum settings. Chip does not do UDP checksum when fragmentation occurs. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 1 + drivers/net/qlge/qlge_main.c | 41 ++++++++++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 13 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index 9918106f2a5..fcb159e4df5 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -977,6 +977,7 @@ struct ib_mac_iocb_rsp { u8 flags1; #define IB_MAC_IOCB_RSP_OI 0x01 /* Overide intr delay */ #define IB_MAC_IOCB_RSP_I 0x02 /* Disble Intr Generation */ +#define IB_MAC_CSUM_ERR_MASK 0x1c /* A mask to use for csum errs */ #define IB_MAC_IOCB_RSP_TE 0x04 /* Checksum error */ #define IB_MAC_IOCB_RSP_NU 0x08 /* No checksum rcvd */ #define IB_MAC_IOCB_RSP_IE 0x10 /* IPv4 checksum error */ diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index bc04aebc928..498d4bf5211 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1531,22 +1531,37 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) { QPRINTK(qdev, RX_STATUS, DEBUG, "Promiscuous Packet.\n"); } - if (ib_mac_rsp->flags1 & (IB_MAC_IOCB_RSP_IE | IB_MAC_IOCB_RSP_TE)) { - QPRINTK(qdev, RX_STATUS, ERR, - "Bad checksum for this %s packet.\n", - ((ib_mac_rsp-> - flags2 & IB_MAC_IOCB_RSP_T) ? "TCP" : "UDP")); - skb->ip_summed = CHECKSUM_NONE; - } else if (qdev->rx_csum && - ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) || - ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) && - !(ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_NU)))) { - QPRINTK(qdev, RX_STATUS, DEBUG, "RX checksum done!\n"); - skb->ip_summed = CHECKSUM_UNNECESSARY; + + + skb->protocol = eth_type_trans(skb, ndev); + skb->ip_summed = CHECKSUM_NONE; + + /* If rx checksum is on, and there are no + * csum or frame errors. + */ + if (qdev->rx_csum && + !(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) && + !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { + /* TCP frame. */ + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { + QPRINTK(qdev, RX_STATUS, DEBUG, + "TCP checksum done!\n"); + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) && + (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) { + /* Unfragmented ipv4 UDP frame. */ + struct iphdr *iph = (struct iphdr *) skb->data; + if (!(iph->frag_off & + cpu_to_be16(IP_MF|IP_OFFSET))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + QPRINTK(qdev, RX_STATUS, DEBUG, + "TCP checksum done!\n"); + } + } } + qdev->stats.rx_packets++; qdev->stats.rx_bytes += skb->len; - skb->protocol = eth_type_trans(skb, ndev); skb_record_rx_queue(skb, rx_ring - &qdev->rx_ring[0]); if (qdev->vlgrp && (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V)) { QPRINTK(qdev, RX_STATUS, DEBUG, -- cgit v1.2.3-70-g09d2 From 22bdd4f599b87734b7fc8137f47e62c13ab27e93 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 9 Mar 2009 10:59:20 +0000 Subject: qlge: Add support for GRO. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 498d4bf5211..339e1da77e6 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1507,6 +1507,8 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, { struct net_device *ndev = qdev->ndev; struct sk_buff *skb = NULL; + u16 vlan_id = (le16_to_cpu(ib_mac_rsp->vlan_id) & + IB_MAC_IOCB_RSP_VLAN_MASK) QL_DUMP_IB_MAC_RSP(ib_mac_rsp); @@ -1562,16 +1564,23 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, qdev->stats.rx_packets++; qdev->stats.rx_bytes += skb->len; - skb_record_rx_queue(skb, rx_ring - &qdev->rx_ring[0]); - if (qdev->vlgrp && (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V)) { - QPRINTK(qdev, RX_STATUS, DEBUG, - "Passing a VLAN packet upstream.\n"); - vlan_hwaccel_receive_skb(skb, qdev->vlgrp, - le16_to_cpu(ib_mac_rsp->vlan_id)); + skb_record_rx_queue(skb, + rx_ring->cq_id - qdev->rss_ring_first_cq_id); + if (skb->ip_summed == CHECKSUM_UNNECESSARY) { + if (qdev->vlgrp && + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) && + (vlan_id != 0)) + vlan_gro_receive(&rx_ring->napi, qdev->vlgrp, + vlan_id, skb); + else + napi_gro_receive(&rx_ring->napi, skb); } else { - QPRINTK(qdev, RX_STATUS, DEBUG, - "Passing a normal packet upstream.\n"); - netif_receive_skb(skb); + if (qdev->vlgrp && + (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) && + (vlan_id != 0)) + vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id); + else + netif_receive_skb(skb); } } @@ -1774,7 +1783,7 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget) rx_ring->cq_id); if (work_done < budget) { - __napi_complete(napi); + napi_complete(napi); ql_enable_completion_interrupt(qdev, rx_ring->irq); } return work_done; @@ -3840,6 +3849,7 @@ static int __devinit qlge_probe(struct pci_dev *pdev, | NETIF_F_TSO_ECN | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER); + ndev->features |= NETIF_F_GRO; if (test_bit(QL_DMA64, &qdev->flags)) ndev->features |= NETIF_F_HIGHDMA; -- cgit v1.2.3-70-g09d2 From 1e213303d8ef2a5d43fb64d2b373858ef70cc79b Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 9 Mar 2009 10:59:21 +0000 Subject: qlge: Add tx multiqueue support. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 339e1da77e6..6da8901b0cc 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1627,14 +1627,12 @@ static void ql_process_mac_tx_intr(struct ql_adapter *qdev, /* Fire up a handler to reset the MPI processor. */ void ql_queue_fw_error(struct ql_adapter *qdev) { - netif_stop_queue(qdev->ndev); netif_carrier_off(qdev->ndev); queue_delayed_work(qdev->workqueue, &qdev->mpi_reset_work, 0); } void ql_queue_asic_error(struct ql_adapter *qdev) { - netif_stop_queue(qdev->ndev); netif_carrier_off(qdev->ndev); ql_disable_interrupts(qdev); /* Clear adapter up bit to signal the recovery @@ -1689,6 +1687,7 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring) struct ob_mac_iocb_rsp *net_rsp = NULL; int count = 0; + struct tx_ring *tx_ring; /* While there are entries in the completion queue. */ while (prod != rx_ring->cnsmr_idx) { @@ -1714,15 +1713,16 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring) prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg); } ql_write_cq_idx(rx_ring); - if (netif_queue_stopped(qdev->ndev) && net_rsp != NULL) { - struct tx_ring *tx_ring = &qdev->tx_ring[net_rsp->txq_idx]; + tx_ring = &qdev->tx_ring[net_rsp->txq_idx]; + if (__netif_subqueue_stopped(qdev->ndev, tx_ring->wq_id) && + net_rsp != NULL) { if (atomic_read(&tx_ring->queue_stopped) && (atomic_read(&tx_ring->tx_count) > (tx_ring->wq_len / 4))) /* * The queue got stopped because the tx_ring was full. * Wake it up, because it's now at least 25% empty. */ - netif_wake_queue(qdev->ndev); + netif_wake_subqueue(qdev->ndev, tx_ring->wq_id); } return count; @@ -2054,7 +2054,7 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev) struct ql_adapter *qdev = netdev_priv(ndev); int tso; struct tx_ring *tx_ring; - u32 tx_ring_idx = (u32) QL_TXQ_IDX(qdev, skb); + u32 tx_ring_idx = (u32) skb->queue_mapping; tx_ring = &qdev->tx_ring[tx_ring_idx]; @@ -2062,7 +2062,7 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev) QPRINTK(qdev, TX_QUEUED, INFO, "%s: shutting down tx queue %d du to lack of resources.\n", __func__, tx_ring_idx); - netif_stop_queue(ndev); + netif_stop_subqueue(ndev, tx_ring->wq_id); atomic_inc(&tx_ring->queue_stopped); return NETDEV_TX_BUSY; } @@ -3192,12 +3192,10 @@ static void ql_display_dev_info(struct net_device *ndev) static int ql_adapter_down(struct ql_adapter *qdev) { - struct net_device *ndev = qdev->ndev; int i, status = 0; struct rx_ring *rx_ring; - netif_stop_queue(ndev); - netif_carrier_off(ndev); + netif_carrier_off(qdev->ndev); /* Don't kill the reset worker thread if we * are in the process of recovery. @@ -3261,12 +3259,11 @@ static int ql_adapter_up(struct ql_adapter *qdev) spin_unlock(&qdev->hw_lock); set_bit(QL_ADAPTER_UP, &qdev->flags); ql_alloc_rx_buffers(qdev); + if ((ql_read32(qdev, STS) & qdev->port_init)) + netif_carrier_on(qdev->ndev); ql_enable_interrupts(qdev); ql_enable_all_completion_interrupts(qdev); - if ((ql_read32(qdev, STS) & qdev->port_init)) { - netif_carrier_on(qdev->ndev); - netif_start_queue(qdev->ndev); - } + netif_tx_start_all_queues(qdev->ndev); return 0; err_init: @@ -3354,6 +3351,7 @@ static int ql_configure_rings(struct ql_adapter *qdev) * completion handler rx_rings. */ qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1; + netif_set_gso_max_size(qdev->ndev, 65536); for (i = 0; i < qdev->tx_ring_count; i++) { tx_ring = &qdev->tx_ring[i]; @@ -3829,7 +3827,8 @@ static int __devinit qlge_probe(struct pci_dev *pdev, static int cards_found = 0; int err = 0; - ndev = alloc_etherdev(sizeof(struct ql_adapter)); + ndev = alloc_etherdev_mq(sizeof(struct ql_adapter), + min(MAX_CPUS, (int)num_online_cpus())); if (!ndev) return -ENOMEM; @@ -3872,7 +3871,6 @@ static int __devinit qlge_probe(struct pci_dev *pdev, return err; } netif_carrier_off(ndev); - netif_stop_queue(ndev); ql_display_dev_info(ndev); cards_found++; return 0; @@ -3926,7 +3924,6 @@ static pci_ers_result_t qlge_io_slot_reset(struct pci_dev *pdev) pci_set_master(pdev); netif_carrier_off(ndev); - netif_stop_queue(ndev); ql_adapter_reset(qdev); /* Make sure the EEPROM is good */ -- cgit v1.2.3-70-g09d2 From c9cf0a04a0c20c26388c51052296d774ec92e2bd Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 9 Mar 2009 10:59:22 +0000 Subject: qlge: bugfix: Tell hw to strip vlan header. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 6da8901b0cc..8b6128e7f5c 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3073,9 +3073,9 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) mask = value << 16; ql_write32(qdev, SYS, mask | value); - /* Set the default queue. */ - value = NIC_RCV_CFG_DFQ; - mask = NIC_RCV_CFG_DFQ_MASK; + /* Set the default queue, and VLAN behavior. */ + value = NIC_RCV_CFG_DFQ | NIC_RCV_CFG_RV; + mask = NIC_RCV_CFG_DFQ_MASK | (NIC_RCV_CFG_RV << 16); ql_write32(qdev, NIC_RCV_CFG, (mask | value)); /* Set the MPI interrupt to enabled. */ -- cgit v1.2.3-70-g09d2 From 08b1bc8f4aba4ddbc4ccef7ebc899e6faae81bbf Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 9 Mar 2009 10:59:23 +0000 Subject: qlge: Get rid of irqsave/restore in intr disable. The completion interrupt disable routine is only called from the ISR, so there is no need for irqsave/restore. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 8b6128e7f5c..45ad4cc298b 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -587,7 +587,6 @@ u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr) static u32 ql_disable_completion_interrupt(struct ql_adapter *qdev, u32 intr) { u32 var = 0; - unsigned long hw_flags; struct intr_context *ctx; /* HW disables for us if we're MSIX multi interrupts and @@ -597,14 +596,14 @@ static u32 ql_disable_completion_interrupt(struct ql_adapter *qdev, u32 intr) return 0; ctx = qdev->intr_context + intr; - spin_lock_irqsave(&qdev->hw_lock, hw_flags); + spin_lock(&qdev->hw_lock); if (!atomic_read(&ctx->irq_cnt)) { ql_write32(qdev, INTR_EN, ctx->intr_dis_mask); var = ql_read32(qdev, STS); } atomic_inc(&ctx->irq_cnt); - spin_unlock_irqrestore(&qdev->hw_lock, hw_flags); + spin_unlock(&qdev->hw_lock); return var; } -- cgit v1.2.3-70-g09d2 From b25215d0433f6c71b68eede3548815196a2ed5d5 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 9 Mar 2009 10:59:24 +0000 Subject: qlge: Clear shadow registers before use. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 45ad4cc298b..75ad4dbb5cb 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2142,6 +2142,7 @@ static int ql_alloc_shadow_space(struct ql_adapter *qdev) "Allocation of RX shadow space failed.\n"); return -ENOMEM; } + memset(qdev->rx_ring_shadow_reg_area, 0, PAGE_SIZE); qdev->tx_ring_shadow_reg_area = pci_alloc_consistent(qdev->pdev, PAGE_SIZE, &qdev->tx_ring_shadow_reg_dma); @@ -2150,6 +2151,7 @@ static int ql_alloc_shadow_space(struct ql_adapter *qdev) "Allocation of TX shadow space failed.\n"); goto err_wqp_sh_area; } + memset(qdev->tx_ring_shadow_reg_area, 0, PAGE_SIZE); return 0; err_wqp_sh_area: -- cgit v1.2.3-70-g09d2 From 39a28bc480bff0f778d043877aff2fd16ad5f769 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 9 Mar 2009 10:59:25 +0000 Subject: qlge: Remove spinlock from asic init path. There is nothing to contend with it. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 75ad4dbb5cb..f7f104ab5ff 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3250,14 +3250,12 @@ static int ql_adapter_up(struct ql_adapter *qdev) { int err = 0; - spin_lock(&qdev->hw_lock); err = ql_adapter_initialize(qdev); if (err) { QPRINTK(qdev, IFUP, INFO, "Unable to initialize adapter.\n"); spin_unlock(&qdev->hw_lock); goto err_init; } - spin_unlock(&qdev->hw_lock); set_bit(QL_ADAPTER_UP, &qdev->flags); ql_alloc_rx_buffers(qdev); if ((ql_read32(qdev, STS) & qdev->port_init)) -- cgit v1.2.3-70-g09d2 From 6b318cb36813d03dd20f80e63c37176a55edae30 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 9 Mar 2009 10:59:26 +0000 Subject: qlge: bugfix: Move netif_napi_del() to common call point. Moving netif_napi_del() up the call chain so it will get called from all exit points. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index f7f104ab5ff..ce826da6f16 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3236,6 +3236,11 @@ static int ql_adapter_down(struct ql_adapter *qdev) ql_tx_ring_clean(qdev); + /* Call netif_napi_del() from common point. + */ + for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) + netif_napi_del(&qdev->rx_ring[i].napi); + ql_free_rx_buffers(qdev); spin_lock(&qdev->hw_lock); status = ql_adapter_reset(qdev); @@ -3964,7 +3969,7 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *ndev = pci_get_drvdata(pdev); struct ql_adapter *qdev = netdev_priv(ndev); - int err, i; + int err; netif_device_detach(ndev); @@ -3974,9 +3979,6 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state) return err; } - for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) - netif_napi_del(&qdev->rx_ring[i].napi); - err = pci_save_state(pdev); if (err) return err; -- cgit v1.2.3-70-g09d2 From 74c50b4bae225b8e5aff9a1ceca256ba46c665c6 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 9 Mar 2009 10:59:27 +0000 Subject: qlge: bugfix: Pad outbound frames smaller than 60 bytes. With some asic configurations xmit of frames smaller than 60 bytes may fail. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index ce826da6f16..189584684aa 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2057,6 +2057,9 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev) tx_ring = &qdev->tx_ring[tx_ring_idx]; + if (skb_padto(skb, ETH_ZLEN)) + return NETDEV_TX_OK; + if (unlikely(atomic_read(&tx_ring->tx_count) < 2)) { QPRINTK(qdev, TX_QUEUED, INFO, "%s: shutting down tx queue %d du to lack of resources.\n", -- cgit v1.2.3-70-g09d2 From d4a4aba61731ce6d102a6a93e22b8fa26511c9d5 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Mon, 9 Mar 2009 10:59:28 +0000 Subject: qlge: bugfix: Fix endian issue related to rx buffers. This was introduced in an earlier net-next patch. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 189584684aa..b91b700a081 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2526,6 +2526,7 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) qdev->doorbell_area + (DB_PAGE_SIZE * (128 + rx_ring->cq_id)); int err = 0; u16 bq_len; + u64 tmp; /* Set up the shadow registers for this ring. */ rx_ring->prod_idx_sh_reg = shadow_reg; @@ -2571,7 +2572,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) FLAGS_LI; /* Load irq delay values */ if (rx_ring->lbq_len) { cqicb->flags |= FLAGS_LL; /* Load lbq values */ - *((u64 *) rx_ring->lbq_base_indirect) = rx_ring->lbq_base_dma; + tmp = (u64)rx_ring->lbq_base_dma;; + *((__le64 *) rx_ring->lbq_base_indirect) = cpu_to_le64(tmp); cqicb->lbq_addr = cpu_to_le64(rx_ring->lbq_base_indirect_dma); bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 : @@ -2587,11 +2589,12 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) } if (rx_ring->sbq_len) { cqicb->flags |= FLAGS_LS; /* Load sbq values */ - *((u64 *) rx_ring->sbq_base_indirect) = rx_ring->sbq_base_dma; + tmp = (u64)rx_ring->sbq_base_dma;; + *((__le64 *) rx_ring->sbq_base_indirect) = cpu_to_le64(tmp); cqicb->sbq_addr = cpu_to_le64(rx_ring->sbq_base_indirect_dma); cqicb->sbq_buf_size = - cpu_to_le16(((rx_ring->sbq_buf_size / 2) + 8) & 0xfffffff8); + cpu_to_le16((u16)(rx_ring->sbq_buf_size/2)); bq_len = (rx_ring->sbq_len == 65536) ? 0 : (u16) rx_ring->sbq_len; cqicb->sbq_len = cpu_to_le16(bq_len); -- cgit v1.2.3-70-g09d2 From c3c6496dc3d94d87bb0da86cf0bf48764577bf77 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Wed, 11 Mar 2009 11:55:40 +0000 Subject: qlge: bugfix: Increase filter on inbound csum. Chip does not do UDP checksum when fragmentation occurs. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge.h | 1 + drivers/net/qlge/qlge_main.c | 38 ++++++++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 12 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h index e6fdce9206c..aff9c5fec73 100644 --- a/drivers/net/qlge/qlge.h +++ b/drivers/net/qlge/qlge.h @@ -927,6 +927,7 @@ struct ib_mac_iocb_rsp { u8 flags1; #define IB_MAC_IOCB_RSP_OI 0x01 /* Overide intr delay */ #define IB_MAC_IOCB_RSP_I 0x02 /* Disble Intr Generation */ +#define IB_MAC_CSUM_ERR_MASK 0x1c /* A mask to use for csum errs */ #define IB_MAC_IOCB_RSP_TE 0x04 /* Checksum error */ #define IB_MAC_IOCB_RSP_NU 0x08 /* No checksum rcvd */ #define IB_MAC_IOCB_RSP_IE 0x10 /* IPv4 checksum error */ diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 8ea72dc60f7..87787b1ecab 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1436,18 +1436,32 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) { QPRINTK(qdev, RX_STATUS, DEBUG, "Promiscuous Packet.\n"); } - if (ib_mac_rsp->flags1 & (IB_MAC_IOCB_RSP_IE | IB_MAC_IOCB_RSP_TE)) { - QPRINTK(qdev, RX_STATUS, ERR, - "Bad checksum for this %s packet.\n", - ((ib_mac_rsp-> - flags2 & IB_MAC_IOCB_RSP_T) ? "TCP" : "UDP")); - skb->ip_summed = CHECKSUM_NONE; - } else if (qdev->rx_csum && - ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) || - ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) && - !(ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_NU)))) { - QPRINTK(qdev, RX_STATUS, DEBUG, "RX checksum done!\n"); - skb->ip_summed = CHECKSUM_UNNECESSARY; + + skb->protocol = eth_type_trans(skb, ndev); + skb->ip_summed = CHECKSUM_NONE; + + /* If rx checksum is on, and there are no + * csum or frame errors. + */ + if (qdev->rx_csum && + !(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) && + !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) { + /* TCP frame. */ + if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) { + QPRINTK(qdev, RX_STATUS, DEBUG, + "TCP checksum done!\n"); + skb->ip_summed = CHECKSUM_UNNECESSARY; + } else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) && + (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) { + /* Unfragmented ipv4 UDP frame. */ + struct iphdr *iph = (struct iphdr *) skb->data; + if (!(iph->frag_off & + cpu_to_be16(IP_MF|IP_OFFSET))) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + QPRINTK(qdev, RX_STATUS, DEBUG, + "TCP checksum done!\n"); + } + } } qdev->stats.rx_packets++; qdev->stats.rx_bytes += skb->len; -- cgit v1.2.3-70-g09d2 From a7a655f22c75f48e0afe8b86be03ecd70bd68b07 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Wed, 11 Mar 2009 11:55:41 +0000 Subject: qlge: bugfix: Tell hw to strip vlan header. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 87787b1ecab..54d54ea03d4 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -2984,9 +2984,9 @@ static int ql_adapter_initialize(struct ql_adapter *qdev) mask = value << 16; ql_write32(qdev, SYS, mask | value); - /* Set the default queue. */ - value = NIC_RCV_CFG_DFQ; - mask = NIC_RCV_CFG_DFQ_MASK; + /* Set the default queue, and VLAN behavior. */ + value = NIC_RCV_CFG_DFQ | NIC_RCV_CFG_RV; + mask = NIC_RCV_CFG_DFQ_MASK | (NIC_RCV_CFG_RV << 16); ql_write32(qdev, NIC_RCV_CFG, (mask | value)); /* Set the MPI interrupt to enabled. */ -- cgit v1.2.3-70-g09d2 From 6612a6344aba8ba7b5af67cd006453bfedbb2967 Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Wed, 11 Mar 2009 11:55:42 +0000 Subject: qlge: bugfix: Move netif_napi_del() to common call point. Moving netif_napi_del() up the call chain so it will get called from all exit points. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 54d54ea03d4..00c37c0f8a9 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -3163,6 +3163,11 @@ static int ql_adapter_down(struct ql_adapter *qdev) ql_tx_ring_clean(qdev); + /* Call netif_napi_del() from common point. + */ + for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) + netif_napi_del(&qdev->rx_ring[i].napi); + spin_lock(&qdev->hw_lock); status = ql_adapter_reset(qdev); if (status) @@ -3867,7 +3872,7 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *ndev = pci_get_drvdata(pdev); struct ql_adapter *qdev = netdev_priv(ndev); - int err, i; + int err; netif_device_detach(ndev); @@ -3877,9 +3882,6 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state) return err; } - for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) - netif_napi_del(&qdev->rx_ring[i].napi); - err = pci_save_state(pdev); if (err) return err; -- cgit v1.2.3-70-g09d2 From 855b0993f216a9b0f9cb33573bd05e314105d86c Mon Sep 17 00:00:00 2001 From: Ron Mercer Date: Wed, 11 Mar 2009 11:55:43 +0000 Subject: qlge: bugfix: Pad outbound frames smaller than 60 bytes. With some asic configurations xmit of frames smaller than 60 bytes may fail. Signed-off-by: Ron Mercer Signed-off-by: David S. Miller --- drivers/net/qlge/qlge_main.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/net/qlge/qlge_main.c') diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index 00c37c0f8a9..91191f761fb 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -1941,6 +1941,9 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev) tx_ring = &qdev->tx_ring[tx_ring_idx]; + if (skb_padto(skb, ETH_ZLEN)) + return NETDEV_TX_OK; + if (unlikely(atomic_read(&tx_ring->tx_count) < 2)) { QPRINTK(qdev, TX_QUEUED, INFO, "%s: shutting down tx queue %d du to lack of resources.\n", -- cgit v1.2.3-70-g09d2