From 489b10c1f63fafcb89c330a0603694652068132a Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 3 Oct 2006 16:39:12 -0700 Subject: [PATCH] sky2: incorrect length on receive packets The previous change to do fragmented receive (post 2.6.18) introduced a bug where packets are passed up with size set to the size of the receive buffer not the actual received data. IP silently trims this so it didn't show up right away. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 396e7df3c61..68515150ff3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1907,7 +1907,7 @@ static struct sk_buff *receive_copy(struct sky2_port *sky2, pci_dma_sync_single_for_device(sky2->hw->pdev, re->data_addr, length, PCI_DMA_FROMDEVICE); re->skb->ip_summed = CHECKSUM_NONE; - __skb_put(skb, length); + skb_put(skb, length); } return skb; } @@ -1970,7 +1970,7 @@ static struct sk_buff *receive_new(struct sky2_port *sky2, if (skb_shinfo(skb)->nr_frags) skb_put_frags(skb, hdr_space, length); else - skb_put(skb, hdr_space); + skb_put(skb, length); return skb; } -- cgit v1.2.3-70-g09d2 From bbedefccc6b0da43cfaf785dac89c88bc59cb6ed Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 3 Oct 2006 12:24:23 -0500 Subject: [PATCH] ibmveth: Harden driver initilisation This patch has been floating around for a while now, Santi originally sent it in March: http://www.spinics.net/lists/netdev/msg00471.html After a kexec the ibmveth driver will fail when trying to register with the Hypervisor because the previous kernel has not unregistered. So if the registration fails, we unregister and then try again. We don't unconditionally unregister, because we don't want to disturb the regular code path for 99% of users. Signed-off-by: Michael Ellerman Acked-by: Anton Blanchard Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 767203d35bc..df3a59efa7a 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -437,6 +437,31 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter) &adapter->rx_buff_pool[i]); } +static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter, + union ibmveth_buf_desc rxq_desc, u64 mac_address) +{ + int rc, try_again = 1; + + /* After a kexec the adapter will still be open, so our attempt to + * open it will fail. So if we get a failure we free the adapter and + * try again, but only once. */ +retry: + rc = h_register_logical_lan(adapter->vdev->unit_address, + adapter->buffer_list_dma, rxq_desc.desc, + adapter->filter_list_dma, mac_address); + + if (rc != H_SUCCESS && try_again) { + do { + rc = h_free_logical_lan(adapter->vdev->unit_address); + } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY)); + + try_again = 0; + goto retry; + } + + return rc; +} + static int ibmveth_open(struct net_device *netdev) { struct ibmveth_adapter *adapter = netdev->priv; @@ -502,12 +527,7 @@ static int ibmveth_open(struct net_device *netdev) ibmveth_debug_printk("filter list @ 0x%p\n", adapter->filter_list_addr); ibmveth_debug_printk("receive q @ 0x%p\n", adapter->rx_queue.queue_addr); - - lpar_rc = h_register_logical_lan(adapter->vdev->unit_address, - adapter->buffer_list_dma, - rxq_desc.desc, - adapter->filter_list_dma, - mac_address); + lpar_rc = ibmveth_register_logical_lan(adapter, rxq_desc, mac_address); if(lpar_rc != H_SUCCESS) { ibmveth_error_printk("h_register_logical_lan failed with %ld\n", lpar_rc); -- cgit v1.2.3-70-g09d2 From 6b4223748895ed5b200c8049231567ea399fc0c2 Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Tue, 3 Oct 2006 12:24:28 -0500 Subject: [PATCH] ibmveth: Add netpoll function This patch adds the net poll controller function to ibmveth to support netconsole and netdump. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index df3a59efa7a..bd79d67c0e9 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -925,6 +925,14 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void ibmveth_poll_controller(struct net_device *dev) +{ + ibmveth_replenish_task(dev->priv); + ibmveth_interrupt(dev->irq, dev, NULL); +} +#endif + static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) { int rc, i; @@ -997,6 +1005,9 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ netdev->ethtool_ops = &netdev_ethtool_ops; netdev->change_mtu = ibmveth_change_mtu; SET_NETDEV_DEV(netdev, &dev->dev); +#ifdef CONFIG_NET_POLL_CONTROLLER + netdev->poll_controller = ibmveth_poll_controller; +#endif netdev->features |= NETIF_F_LLTX; spin_lock_init(&adapter->stats_lock); -- cgit v1.2.3-70-g09d2 From 4347ef15f76dca33ae8da769d6900a468253bda2 Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Tue, 3 Oct 2006 12:24:34 -0500 Subject: [PATCH] ibmveth: kdump interrupt fix This patch fixes a race that panics the kernel when opening the device after a kdump. Without this patch there is a window where the hypervisor can send an interrupt before all the structures for the kdump ibmveth module are ready (because the hypervisor is not aware that the partition crashed and that the virtual driver is reloading). We close this window by disabling the interrupts before registering the adapter to the hypervisor. This patch depends on the "ibmveth: Harden driver initilisation" patch. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index bd79d67c0e9..2ec49d25453 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -527,6 +527,8 @@ static int ibmveth_open(struct net_device *netdev) ibmveth_debug_printk("filter list @ 0x%p\n", adapter->filter_list_addr); ibmveth_debug_printk("receive q @ 0x%p\n", adapter->rx_queue.queue_addr); + h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); + lpar_rc = ibmveth_register_logical_lan(adapter, rxq_desc, mac_address); if(lpar_rc != H_SUCCESS) { -- cgit v1.2.3-70-g09d2 From 03a85d0907b2455c772b8fb179b0c07a66b00ddb Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Tue, 3 Oct 2006 12:24:39 -0500 Subject: [PATCH] ibmveth: rename proc entry name This patch changes the name of the proc file for each ibmveth adapter from the network device name to the slot number in the virtual bus. The proc file is created when the device is probed, so a change in the name of the device will not be reflected in the name of the proc file giving problems when identifying and removing the adapter. The slot number is a property that does not change through the life of the adapter so we use that instead. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 2ec49d25453..6aff2bc3df5 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -1165,7 +1165,9 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) { struct proc_dir_entry *entry; if (ibmveth_proc_dir) { - entry = create_proc_entry(adapter->netdev->name, S_IFREG, ibmveth_proc_dir); + char u_addr[10]; + sprintf(u_addr, "%x", adapter->vdev->unit_address); + entry = create_proc_entry(u_addr, S_IFREG, ibmveth_proc_dir); if (!entry) { ibmveth_error_printk("Cannot create adapter proc entry"); } else { @@ -1180,7 +1182,9 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter) static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter) { if (ibmveth_proc_dir) { - remove_proc_entry(adapter->netdev->name, ibmveth_proc_dir); + char u_addr[10]; + sprintf(u_addr, "%x", adapter->vdev->unit_address); + remove_proc_entry(u_addr, ibmveth_proc_dir); } } -- cgit v1.2.3-70-g09d2 From 751ae21c6cd1493e3d0a4935b08fb298b9d89773 Mon Sep 17 00:00:00 2001 From: Santiago Leon Date: Tue, 3 Oct 2006 12:24:45 -0500 Subject: [PATCH] ibmveth: fix int rollover panic This patch fixes a nasty bug that has been sitting there since the very first versions of the driver, but is generating a panic because we changed the number of 2K buffers for 2.6.16. The consumer_index and producer_index are u32's that get incremented on every buffer emptied and replenished respectively. We use the {producer,consumer}_index mod'ed with the size of the pool to pick out an entry in the free_map. The problem happens when the u32 rolls over and the number of the buffers in the pool is not a perfect divisor of 2^32. i.e. if the number of 2K buffers is 0x300, before the consumer_index rolls over, our index to the free map = 0xffffffff mod 0x300 = 0xff. The next time a buffer is emptied, we want the index to the free map to be 0x100, but 0x0 mod 0x300 is 0x0. This patch assigns the mod'ed result back to the consumer and producer indexes so that they never roll over. The second chunk of the patch covers the unlikely case where the consumer_index has just been reset to 0x0 and the hypervisor is not able to accept that buffer. Signed-off-by: Santiago Leon Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 6aff2bc3df5..16f3faa7ea5 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -213,6 +213,7 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc } free_index = pool->consumer_index++ % pool->size; + pool->consumer_index = free_index; index = pool->free_map[free_index]; ibmveth_assert(index != IBM_VETH_INVALID_MAP); @@ -238,7 +239,10 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc if(lpar_rc != H_SUCCESS) { pool->free_map[free_index] = index; pool->skbuff[index] = NULL; - pool->consumer_index--; + if (pool->consumer_index == 0) + pool->consumer_index = pool->size - 1; + else + pool->consumer_index--; dma_unmap_single(&adapter->vdev->dev, pool->dma_addr[index], pool->buff_size, DMA_FROM_DEVICE); @@ -326,6 +330,7 @@ static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter, u64 DMA_FROM_DEVICE); free_index = adapter->rx_buff_pool[pool].producer_index++ % adapter->rx_buff_pool[pool].size; + adapter->rx_buff_pool[pool].producer_index = free_index; adapter->rx_buff_pool[pool].free_map[free_index] = index; mb(); -- cgit v1.2.3-70-g09d2 From 70fbf32703a9c4d3403663d1fc24fd8afc76d56f Mon Sep 17 00:00:00 2001 From: Maxime Bizon Date: Tue, 3 Oct 2006 10:27:10 -0700 Subject: [PATCH] mv643xx_eth: Fix ethtool stats Some stats reported by ethtool -S on mv643xx_eth device are cleared between each call. This patch fixes it. Signed-off-by: Maxime Bizon Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 7f8e5ad1b70..eccedf3e627 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2156,7 +2156,7 @@ static void eth_update_mib_counters(struct mv643xx_private *mp) for (offset = ETH_MIB_BAD_OCTETS_RECEIVED; offset <= ETH_MIB_FRAMES_1024_TO_MAX_OCTETS; offset += 4) - *(u32 *)((char *)p + offset) = read_mib(mp, offset); + *(u32 *)((char *)p + offset) += read_mib(mp, offset); p->good_octets_sent += read_mib(mp, ETH_MIB_GOOD_OCTETS_SENT_LOW); p->good_octets_sent += @@ -2165,7 +2165,7 @@ static void eth_update_mib_counters(struct mv643xx_private *mp) for (offset = ETH_MIB_GOOD_FRAMES_SENT; offset <= ETH_MIB_LATE_COLLISION; offset += 4) - *(u32 *)((char *)p + offset) = read_mib(mp, offset); + *(u32 *)((char *)p + offset) += read_mib(mp, offset); } /* -- cgit v1.2.3-70-g09d2 From 0a07bc645e818b88559d99f52ad45e35352e8228 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Tue, 19 Sep 2006 14:55:22 +0200 Subject: [PATCH] forcedeth: hardirq lockdep warning BUG: warning at kernel/lockdep.c:1816/trace_hardirqs_on() (Not tainted) Call Trace: show_trace dump_stack trace_hardirqs_on :forcedeth:nv_nic_irq_other handle_IRQ_event __do_IRQ do_IRQ ret_from_intr DWARF2 barf default_idle cpu_idle rest_init start_kernel _sinittext These 3 functions nv_nic_irq_tx(), nv_nic_irq_rx() and nv_nic_irq_other() are reachable from IRQ context and process context. Make use of the irq-save/restore spinlock variant. (Compile tested only, since I do not have the hardware) Signed-off-by: Peter Zijlstra Cc: Jeff Garzik Cc: Ingo Molnar Cc: Arjan van de Ven Cc: Dave Jones Cc: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index eea1d66c530..35467e0ac53 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -2497,6 +2497,7 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs) u8 __iomem *base = get_hwbase(dev); u32 events; int i; + unsigned long flags; dprintk(KERN_DEBUG "%s: nv_nic_irq_tx\n", dev->name); @@ -2508,16 +2509,16 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs) if (!(events & np->irqmask)) break; - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); nv_tx_done(dev); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); if (events & (NVREG_IRQ_TX_ERR)) { dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", dev->name, events); } if (i > max_interrupt_work) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask); pci_push(base); @@ -2527,7 +2528,7 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); break; } @@ -2601,6 +2602,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) u8 __iomem *base = get_hwbase(dev); u32 events; int i; + unsigned long flags; dprintk(KERN_DEBUG "%s: nv_nic_irq_rx\n", dev->name); @@ -2614,14 +2616,14 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) nv_rx_process(dev, dev->weight); if (nv_alloc_rx(dev)) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); } if (i > max_interrupt_work) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); pci_push(base); @@ -2631,7 +2633,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); break; } } @@ -2648,6 +2650,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) u8 __iomem *base = get_hwbase(dev); u32 events; int i; + unsigned long flags; dprintk(KERN_DEBUG "%s: nv_nic_irq_other\n", dev->name); @@ -2660,14 +2663,14 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) break; if (events & NVREG_IRQ_LINK) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); nv_link_irq(dev); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); } if (np->need_linktimer && time_after(jiffies, np->link_timeout)) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); nv_linkchange(dev); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); np->link_timeout = jiffies + LINK_TIMEOUT; } if (events & (NVREG_IRQ_UNKNOWN)) { @@ -2675,7 +2678,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) dev->name, events); } if (i > max_interrupt_work) { - spin_lock_irq(&np->lock); + spin_lock_irqsave(&np->lock, flags); /* disable interrupts on the nic */ writel(NVREG_IRQ_OTHER, base + NvRegIrqMask); pci_push(base); @@ -2685,7 +2688,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) mod_timer(&np->nic_poll, jiffies + POLL_WAIT); } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i); - spin_unlock_irq(&np->lock); + spin_unlock_irqrestore(&np->lock, flags); break; } -- cgit v1.2.3-70-g09d2 From 39984a9fad0c642182f426d7771332d46f222103 Mon Sep 17 00:00:00 2001 From: Karsten Keil Date: Fri, 29 Sep 2006 23:28:42 -0700 Subject: [PATCH] bonding: fix deadlock on high loads in bond_alb_monitor() In bond_alb_monitor the bond->curr_slave_lock write lock is taken and then dev_set_promiscuity maybe called which can take some time, depending on the network HW. If a network IRQ for this card come in the softirq handler maybe try to deliver more packets which end up in a request to the read lock of bond->curr_slave_lock -> deadlock. This issue was found by a test lab during network stress tests, this patch disable the softirq handler for this case and solved the issue. Signed-off-by: Karsten Keil Acked-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_alb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index e83bc825f6a..32923162179 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1433,7 +1433,7 @@ void bond_alb_monitor(struct bonding *bond) * write lock to protect from other code that also * sets the promiscuity. */ - write_lock(&bond->curr_slave_lock); + write_lock_bh(&bond->curr_slave_lock); if (bond_info->primary_is_promisc && (++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) { @@ -1448,7 +1448,7 @@ void bond_alb_monitor(struct bonding *bond) bond_info->primary_is_promisc = 0; } - write_unlock(&bond->curr_slave_lock); + write_unlock_bh(&bond->curr_slave_lock); if (bond_info->rlb_rebalance) { bond_info->rlb_rebalance = 0; -- cgit v1.2.3-70-g09d2 From 2f614fe04f4463ff22234133319067d7361f54e5 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 5 Oct 2006 07:10:38 -0400 Subject: [netdrvr] b44: handle excessive multicast groups If there are more than B44_MCAST_TABLE_SIZE groups in the dev->mc_list, it will only listen to the first B44_MCAST_TABLE_SIZE that it sees. This change makes the driver go into RXCONFIG_ALLMULTI mode if there are more than B44_MCAST_TABLE_SIZE groups being subscribed to, similar to other network drivers. Noticed by Bill Helfinstine Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index e891ea2ecc3..973b8eb37dc 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1706,14 +1706,15 @@ static void __b44_set_rx_mode(struct net_device *dev) __b44_set_mac_addr(bp); - if (dev->flags & IFF_ALLMULTI) + if ((dev->flags & IFF_ALLMULTI) || + (dev->mc_count > B44_MCAST_TABLE_SIZE)) val |= RXCONFIG_ALLMULTI; else i = __b44_load_mcast(bp, dev); - for (; i < 64; i++) { + for (; i < 64; i++) __b44_cam_write(bp, zero, i); - } + bw32(bp, B44_RXCONFIG, val); val = br32(bp, B44_CAM_CTRL); bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE); -- cgit v1.2.3-70-g09d2 From 12f417ee95bf98cd3e42d2a771f7c6d360159b9d Mon Sep 17 00:00:00 2001 From: Deepak Saxena Date: Tue, 10 Oct 2006 14:33:22 -0700 Subject: [PATCH] Update smc91x driver with ARM Versatile board info We need to specify a Versatile-specific SMC_IRQ_FLAGS value or the new generic IRQ layer will complain thusly: No IRQF_TRIGGER set_type function for IRQ 25 () Signed-off-by: Deepak Saxena Cc: Jeff Garzik Cc: Russell King Cc: Nicolas Pitre Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/smc91x.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers') diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 636dbfcdf8c..0c9f1e7dab2 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -398,6 +398,24 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r, #define SMC_IRQ_FLAGS (0) +#elif defined(CONFIG_ARCH_VERSATILE) + +#define SMC_CAN_USE_8BIT 1 +#define SMC_CAN_USE_16BIT 1 +#define SMC_CAN_USE_32BIT 1 +#define SMC_NOWAIT 1 + +#define SMC_inb(a, r) readb((a) + (r)) +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outb(v, a, r) writeb(v, (a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) + +#define SMC_IRQ_FLAGS (0) + #else #define SMC_CAN_USE_8BIT 1 -- cgit v1.2.3-70-g09d2 From 6f62768344e46520ae585f3e201c9d3e497b028f Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 10 Oct 2006 14:33:26 -0700 Subject: [PATCH] b44: fix eeprom endianess issue This fixes eeprom read on big-endian architectures. readw returns the data in CPU order. With cpu_to_le16 we convert it to little endian, because "ptr" is a pointer to a _byte_ arrray. See the cast above. A byte array is little endian. The bug is: Reading u16 values with readw, casting them into an u8 array and accessing this u8 array as an u8 (byte) array. The correct fix is to swap the CPU-ordering value returned by readw into little endian, as the u8 array is little endian. This compiles to nothing on little endian hardware (so it does not change b44 code on LE hardware), but _fixes_ code on BE hardware. Signed-off-by: Michael Buesch Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index ebb726e655a..1ec217433b4 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -2056,7 +2056,7 @@ static int b44_read_eeprom(struct b44 *bp, u8 *data) u16 *ptr = (u16 *) data; for (i = 0; i < 128; i += 2) - ptr[i / 2] = readw(bp->regs + 4096 + i); + ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i)); return 0; } -- cgit v1.2.3-70-g09d2 From 5f77113c01d8a9f8193769d2ca73763047af39ef Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 10 Oct 2006 14:33:30 -0700 Subject: [PATCH] ibmveth irq fix drivers/net/ibmveth.c:939: error: too many arguments to function `ibmveth_interrupt' Cc: Jeff Garzik Cc: Anton Blanchard Cc: Paul Mackerras Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/ibmveth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index bf414a93fac..2802db23d3c 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -936,7 +936,7 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) static void ibmveth_poll_controller(struct net_device *dev) { ibmveth_replenish_task(dev->priv); - ibmveth_interrupt(dev->irq, dev, NULL); + ibmveth_interrupt(dev->irq, dev); } #endif -- cgit v1.2.3-70-g09d2 From 08093c8fd66ef7a8c2f887812cc98c54f5f12703 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Thu, 5 Oct 2006 16:53:12 +0200 Subject: [PATCH] ehea: firmware (hvcall) interface changes This eHEA patch covers required changes related to Anton Blanchard's new hvcall interface. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea_phyp.c | 573 ++++++++++++++++++------------------------- 1 file changed, 238 insertions(+), 335 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c index 4a85aca4c7e..0b51a8cea07 100644 --- a/drivers/net/ehea/ehea_phyp.c +++ b/drivers/net/ehea/ehea_phyp.c @@ -44,71 +44,99 @@ static inline u16 get_order_of_qentries(u16 queue_entries) #define H_ALL_RES_TYPE_MR 5 #define H_ALL_RES_TYPE_MW 6 -static long ehea_hcall_9arg_9ret(unsigned long opcode, - unsigned long arg1, unsigned long arg2, - unsigned long arg3, unsigned long arg4, - unsigned long arg5, unsigned long arg6, - unsigned long arg7, unsigned long arg8, - unsigned long arg9, unsigned long *out1, - unsigned long *out2,unsigned long *out3, - unsigned long *out4,unsigned long *out5, - unsigned long *out6,unsigned long *out7, - unsigned long *out8,unsigned long *out9) +static long ehea_plpar_hcall_norets(unsigned long opcode, + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6, + unsigned long arg7) { - long hret; + long ret; int i, sleep_msecs; for (i = 0; i < 5; i++) { - hret = plpar_hcall_9arg_9ret(opcode,arg1, arg2, arg3, arg4, - arg5, arg6, arg7, arg8, arg9, out1, - out2, out3, out4, out5, out6, out7, - out8, out9); - if (H_IS_LONG_BUSY(hret)) { - sleep_msecs = get_longbusy_msecs(hret); + ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4, + arg5, arg6, arg7); + + if (H_IS_LONG_BUSY(ret)) { + sleep_msecs = get_longbusy_msecs(ret); msleep_interruptible(sleep_msecs); continue; } - if (hret < H_SUCCESS) - ehea_error("op=%lx hret=%lx " - "i1=%lx i2=%lx i3=%lx i4=%lx i5=%lx i6=%lx " - "i7=%lx i8=%lx i9=%lx " - "o1=%lx o2=%lx o3=%lx o4=%lx o5=%lx o6=%lx " - "o7=%lx o8=%lx o9=%lx", - opcode, hret, arg1, arg2, arg3, arg4, arg5, - arg6, arg7, arg8, arg9, *out1, *out2, *out3, - *out4, *out5, *out6, *out7, *out8, *out9); - return hret; + if (ret < H_SUCCESS) + ehea_error("opcode=%lx ret=%lx" + " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" + " arg5=%lx arg6=%lx arg7=%lx ", + opcode, ret, + arg1, arg2, arg3, arg4, arg5, + arg6, arg7); + + return ret; } + return H_BUSY; } -u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category, - const u64 qp_handle, const u64 sel_mask, void *cb_addr) +static long ehea_plpar_hcall9(unsigned long opcode, + unsigned long *outs, /* array of 9 outputs */ + unsigned long arg1, + unsigned long arg2, + unsigned long arg3, + unsigned long arg4, + unsigned long arg5, + unsigned long arg6, + unsigned long arg7, + unsigned long arg8, + unsigned long arg9) { - u64 dummy; + long ret; + int i, sleep_msecs; - if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0) { - ehea_error("not on pageboundary"); - return H_PARAMETER; + for (i = 0; i < 5; i++) { + ret = plpar_hcall9(opcode, outs, + arg1, arg2, arg3, arg4, arg5, + arg6, arg7, arg8, arg9); + + if (H_IS_LONG_BUSY(ret)) { + sleep_msecs = get_longbusy_msecs(ret); + msleep_interruptible(sleep_msecs); + continue; + } + + if (ret < H_SUCCESS) + ehea_error("opcode=%lx ret=%lx" + " arg1=%lx arg2=%lx arg3=%lx arg4=%lx" + " arg5=%lx arg6=%lx arg7=%lx arg8=%lx" + " arg9=%lx" + " out1=%lx out2=%lx out3=%lx out4=%lx" + " out5=%lx out6=%lx out7=%lx out8=%lx" + " out9=%lx", + opcode, ret, + arg1, arg2, arg3, arg4, arg5, + arg6, arg7, arg8, arg9, + outs[0], outs[1], outs[2], outs[3], + outs[4], outs[5], outs[6], outs[7], + outs[8]); + + return ret; } - return ehea_hcall_9arg_9ret(H_QUERY_HEA_QP, - adapter_handle, /* R4 */ - qp_category, /* R5 */ - qp_handle, /* R6 */ - sel_mask, /* R7 */ - virt_to_abs(cb_addr), /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return H_BUSY; +} + +u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category, + const u64 qp_handle, const u64 sel_mask, void *cb_addr) +{ + return ehea_plpar_hcall_norets(H_QUERY_HEA_QP, + adapter_handle, /* R4 */ + qp_category, /* R5 */ + qp_handle, /* R6 */ + sel_mask, /* R7 */ + virt_to_abs(cb_addr), /* R8 */ + 0, 0); } /* input param R5 */ @@ -180,6 +208,7 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle, u64 *qp_handle, struct h_epas *h_epas) { u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; u64 allocate_controls = EHEA_BMASK_SET(H_ALL_RES_QP_EQPO, init_attr->low_lat_rq1 ? 1 : 0) @@ -219,45 +248,29 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle, EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ2, init_attr->rq2_threshold) | EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ3, init_attr->rq3_threshold); - u64 r5_out = 0; - u64 r6_out = 0; - u64 r7_out = 0; - u64 r8_out = 0; - u64 r9_out = 0; - u64 g_la_user_out = 0; - u64 r11_out = 0; - u64 r12_out = 0; - - hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE, - adapter_handle, /* R4 */ - allocate_controls, /* R5 */ - init_attr->send_cq_handle, /* R6 */ - init_attr->recv_cq_handle, /* R7 */ - init_attr->aff_eq_handle, /* R8 */ - r9_reg, /* R9 */ - max_r10_reg, /* R10 */ - r11_in, /* R11 */ - threshold, /* R12 */ - qp_handle, /* R4 */ - &r5_out, /* R5 */ - &r6_out, /* R6 */ - &r7_out, /* R7 */ - &r8_out, /* R8 */ - &r9_out, /* R9 */ - &g_la_user_out, /* R10 */ - &r11_out, /* R11 */ - &r12_out); /* R12 */ - - init_attr->qp_nr = (u32)r5_out; + hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, + outs, + adapter_handle, /* R4 */ + allocate_controls, /* R5 */ + init_attr->send_cq_handle, /* R6 */ + init_attr->recv_cq_handle, /* R7 */ + init_attr->aff_eq_handle, /* R8 */ + r9_reg, /* R9 */ + max_r10_reg, /* R10 */ + r11_in, /* R11 */ + threshold); /* R12 */ + + *qp_handle = outs[0]; + init_attr->qp_nr = (u32)outs[1]; init_attr->act_nr_send_wqes = - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, r6_out); + (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, outs[2]); init_attr->act_nr_rwqes_rq1 = - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, r6_out); + (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, outs[2]); init_attr->act_nr_rwqes_rq2 = - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, r6_out); + (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, outs[2]); init_attr->act_nr_rwqes_rq3 = - (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, r6_out); + (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, outs[2]); init_attr->act_wqe_size_enc_sq = init_attr->wqe_size_enc_sq; init_attr->act_wqe_size_enc_rq1 = init_attr->wqe_size_enc_rq1; @@ -265,25 +278,25 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle, init_attr->act_wqe_size_enc_rq3 = init_attr->wqe_size_enc_rq3; init_attr->nr_sq_pages = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, r8_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, outs[4]); init_attr->nr_rq1_pages = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, r8_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, outs[4]); init_attr->nr_rq2_pages = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, r9_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, outs[5]); init_attr->nr_rq3_pages = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, r9_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, outs[5]); init_attr->liobn_sq = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, r11_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, outs[7]); init_attr->liobn_rq1 = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, r11_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, outs[7]); init_attr->liobn_rq2 = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, r12_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, outs[8]); init_attr->liobn_rq3 = - (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, r12_out); + (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, outs[8]); if (!hret) - hcp_epas_ctor(h_epas, g_la_user_out, g_la_user_out); + hcp_epas_ctor(h_epas, outs[6], outs[6]); return hret; } @@ -292,31 +305,24 @@ u64 ehea_h_alloc_resource_cq(const u64 adapter_handle, struct ehea_cq_attr *cq_attr, u64 *cq_handle, struct h_epas *epas) { - u64 hret, dummy, act_nr_of_cqes_out, act_pages_out; - u64 g_la_privileged_out, g_la_user_out; - - hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE, - adapter_handle, /* R4 */ - H_ALL_RES_TYPE_CQ, /* R5 */ - cq_attr->eq_handle, /* R6 */ - cq_attr->cq_token, /* R7 */ - cq_attr->max_nr_of_cqes, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - cq_handle, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &act_nr_of_cqes_out, /* R7 */ - &act_pages_out, /* R8 */ - &g_la_privileged_out, /* R9 */ - &g_la_user_out, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - - cq_attr->act_nr_of_cqes = act_nr_of_cqes_out; - cq_attr->nr_pages = act_pages_out; + u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, + outs, + adapter_handle, /* R4 */ + H_ALL_RES_TYPE_CQ, /* R5 */ + cq_attr->eq_handle, /* R6 */ + cq_attr->cq_token, /* R7 */ + cq_attr->max_nr_of_cqes, /* R8 */ + 0, 0, 0, 0); /* R9-R12 */ + + *cq_handle = outs[0]; + cq_attr->act_nr_of_cqes = outs[3]; + cq_attr->nr_pages = outs[4]; if (!hret) - hcp_epas_ctor(epas, g_la_privileged_out, g_la_user_out); + hcp_epas_ctor(epas, outs[5], outs[6]); return hret; } @@ -361,9 +367,8 @@ u64 ehea_h_alloc_resource_cq(const u64 adapter_handle, u64 ehea_h_alloc_resource_eq(const u64 adapter_handle, struct ehea_eq_attr *eq_attr, u64 *eq_handle) { - u64 hret, dummy, eq_liobn, allocate_controls; - u64 ist1_out, ist2_out, ist3_out, ist4_out; - u64 act_nr_of_eqes_out, act_pages_out; + u64 hret, allocate_controls; + u64 outs[PLPAR_HCALL9_BUFSIZE]; /* resource type */ allocate_controls = @@ -372,27 +377,20 @@ u64 ehea_h_alloc_resource_eq(const u64 adapter_handle, | EHEA_BMASK_SET(H_ALL_RES_EQ_INH_EQE_GEN, !eq_attr->eqe_gen) | EHEA_BMASK_SET(H_ALL_RES_EQ_NON_NEQ_ISN, 1); - hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE, - adapter_handle, /* R4 */ - allocate_controls, /* R5 */ - eq_attr->max_nr_of_eqes, /* R6 */ - 0, 0, 0, 0, 0, 0, /* R7-R10 */ - eq_handle, /* R4 */ - &dummy, /* R5 */ - &eq_liobn, /* R6 */ - &act_nr_of_eqes_out, /* R7 */ - &act_pages_out, /* R8 */ - &ist1_out, /* R9 */ - &ist2_out, /* R10 */ - &ist3_out, /* R11 */ - &ist4_out); /* R12 */ - - eq_attr->act_nr_of_eqes = act_nr_of_eqes_out; - eq_attr->nr_pages = act_pages_out; - eq_attr->ist1 = ist1_out; - eq_attr->ist2 = ist2_out; - eq_attr->ist3 = ist3_out; - eq_attr->ist4 = ist4_out; + hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, + outs, + adapter_handle, /* R4 */ + allocate_controls, /* R5 */ + eq_attr->max_nr_of_eqes, /* R6 */ + 0, 0, 0, 0, 0, 0); /* R7-R10 */ + + *eq_handle = outs[0]; + eq_attr->act_nr_of_eqes = outs[3]; + eq_attr->nr_pages = outs[4]; + eq_attr->ist1 = outs[5]; + eq_attr->ist2 = outs[6]; + eq_attr->ist3 = outs[7]; + eq_attr->ist4 = outs[8]; return hret; } @@ -402,31 +400,22 @@ u64 ehea_h_modify_ehea_qp(const u64 adapter_handle, const u8 cat, void *cb_addr, u64 *inv_attr_id, u64 *proc_mask, u16 *out_swr, u16 *out_rwr) { - u64 hret, dummy, act_out_swr, act_out_rwr; - - if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0) { - ehea_error("not on page boundary"); - return H_PARAMETER; - } - - hret = ehea_hcall_9arg_9ret(H_MODIFY_HEA_QP, - adapter_handle, /* R4 */ - (u64) cat, /* R5 */ - qp_handle, /* R6 */ - sel_mask, /* R7 */ - virt_to_abs(cb_addr), /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - inv_attr_id, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &act_out_swr, /* R7 */ - &act_out_rwr, /* R8 */ - proc_mask, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - *out_swr = act_out_swr; - *out_rwr = act_out_rwr; + u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + hret = ehea_plpar_hcall9(H_MODIFY_HEA_QP, + outs, + adapter_handle, /* R4 */ + (u64) cat, /* R5 */ + qp_handle, /* R6 */ + sel_mask, /* R7 */ + virt_to_abs(cb_addr), /* R8 */ + 0, 0, 0, 0); /* R9-R12 */ + + *inv_attr_id = outs[0]; + *out_swr = outs[3]; + *out_rwr = outs[4]; + *proc_mask = outs[5]; return hret; } @@ -435,122 +424,81 @@ u64 ehea_h_register_rpage(const u64 adapter_handle, const u8 pagesize, const u8 queue_type, const u64 resource_handle, const u64 log_pageaddr, u64 count) { - u64 dummy, reg_control; + u64 reg_control; reg_control = EHEA_BMASK_SET(H_REG_RPAGE_PAGE_SIZE, pagesize) | EHEA_BMASK_SET(H_REG_RPAGE_QT, queue_type); - return ehea_hcall_9arg_9ret(H_REGISTER_HEA_RPAGES, - adapter_handle, /* R4 */ - reg_control, /* R5 */ - resource_handle, /* R6 */ - log_pageaddr, /* R7 */ - count, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(H_REGISTER_HEA_RPAGES, + adapter_handle, /* R4 */ + reg_control, /* R5 */ + resource_handle, /* R6 */ + log_pageaddr, /* R7 */ + count, /* R8 */ + 0, 0); /* R9-R10 */ } u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle, const u64 vaddr_in, const u32 access_ctrl, const u32 pd, struct ehea_mr *mr) { - u64 hret, dummy, lkey_out; - - hret = ehea_hcall_9arg_9ret(H_REGISTER_SMR, - adapter_handle , /* R4 */ - orig_mr_handle, /* R5 */ - vaddr_in, /* R6 */ - (((u64)access_ctrl) << 32ULL), /* R7 */ - pd, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &mr->handle, /* R4 */ - &dummy, /* R5 */ - &lkey_out, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - mr->lkey = (u32)lkey_out; + u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + hret = ehea_plpar_hcall9(H_REGISTER_SMR, + outs, + adapter_handle , /* R4 */ + orig_mr_handle, /* R5 */ + vaddr_in, /* R6 */ + (((u64)access_ctrl) << 32ULL), /* R7 */ + pd, /* R8 */ + 0, 0, 0, 0); /* R9-R12 */ + + mr->handle = outs[0]; + mr->lkey = (u32)outs[2]; return hret; } u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle) { - u64 hret, dummy, ladr_next_sq_wqe_out; - u64 ladr_next_rq1_wqe_out, ladr_next_rq2_wqe_out, ladr_next_rq3_wqe_out; - - hret = ehea_hcall_9arg_9ret(H_DISABLE_AND_GET_HEA, - adapter_handle, /* R4 */ - H_DISABLE_GET_EHEA_WQE_P, /* R5 */ - qp_handle, /* R6 */ - 0, 0, 0, 0, 0, 0, /* R7-R12 */ - &ladr_next_sq_wqe_out, /* R4 */ - &ladr_next_rq1_wqe_out, /* R5 */ - &ladr_next_rq2_wqe_out, /* R6 */ - &ladr_next_rq3_wqe_out, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - return hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + return ehea_plpar_hcall9(H_DISABLE_AND_GET_HEA, + outs, + adapter_handle, /* R4 */ + H_DISABLE_GET_EHEA_WQE_P, /* R5 */ + qp_handle, /* R6 */ + 0, 0, 0, 0, 0, 0); /* R7-R12 */ } u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle) { - u64 dummy; - - return ehea_hcall_9arg_9ret(H_FREE_RESOURCE, - adapter_handle, /* R4 */ - res_handle, /* R5 */ - 0, 0, 0, 0, 0, 0, 0, /* R6-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(H_FREE_RESOURCE, + adapter_handle, /* R4 */ + res_handle, /* R5 */ + 0, 0, 0, 0, 0); /* R6-R10 */ } u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr, const u64 length, const u32 access_ctrl, const u32 pd, u64 *mr_handle, u32 *lkey) { - u64 hret, dummy, lkey_out; - - hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE, - adapter_handle, /* R4 */ - 5, /* R5 */ - vaddr, /* R6 */ - length, /* R7 */ - (((u64) access_ctrl) << 32ULL),/* R8 */ - pd, /* R9 */ - 0, 0, 0, /* R10-R12 */ - mr_handle, /* R4 */ - &dummy, /* R5 */ - &lkey_out, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ - *lkey = (u32) lkey_out; - + u64 hret; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + + hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE, + outs, + adapter_handle, /* R4 */ + 5, /* R5 */ + vaddr, /* R6 */ + length, /* R7 */ + (((u64) access_ctrl) << 32ULL), /* R8 */ + pd, /* R9 */ + 0, 0, 0); /* R10-R12 */ + + *mr_handle = outs[0]; + *lkey = (u32)outs[2]; return hret; } @@ -570,23 +518,14 @@ u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle, u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr) { - u64 hret, dummy, cb_logaddr; + u64 hret, cb_logaddr; cb_logaddr = virt_to_abs(cb_addr); - hret = ehea_hcall_9arg_9ret(H_QUERY_HEA, - adapter_handle, /* R4 */ - cb_logaddr, /* R5 */ - 0, 0, 0, 0, 0, 0, 0, /* R6-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + hret = ehea_plpar_hcall_norets(H_QUERY_HEA, + adapter_handle, /* R4 */ + cb_logaddr, /* R5 */ + 0, 0, 0, 0, 0); /* R6-R10 */ #ifdef DEBUG ehea_dmp(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea"); #endif @@ -597,36 +536,28 @@ u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num, const u8 cb_cat, const u64 select_mask, void *cb_addr) { - u64 port_info, dummy; + u64 port_info; u64 cb_logaddr = virt_to_abs(cb_addr); u64 arr_index = 0; port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat) | EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num); - return ehea_hcall_9arg_9ret(H_QUERY_HEA_PORT, - adapter_handle, /* R4 */ - port_info, /* R5 */ - select_mask, /* R6 */ - arr_index, /* R7 */ - cb_logaddr, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(H_QUERY_HEA_PORT, + adapter_handle, /* R4 */ + port_info, /* R5 */ + select_mask, /* R6 */ + arr_index, /* R7 */ + cb_logaddr, /* R8 */ + 0, 0); /* R9-R10 */ } u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num, const u8 cb_cat, const u64 select_mask, void *cb_addr) { - u64 port_info, dummy, inv_attr_ident, proc_mask; + u64 outs[PLPAR_HCALL9_BUFSIZE]; + u64 port_info; u64 arr_index = 0; u64 cb_logaddr = virt_to_abs(cb_addr); @@ -635,29 +566,21 @@ u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num, #ifdef DEBUG ehea_dump(cb_addr, sizeof(struct hcp_ehea_port_cb0), "Before HCALL"); #endif - return ehea_hcall_9arg_9ret(H_MODIFY_HEA_PORT, - adapter_handle, /* R4 */ - port_info, /* R5 */ - select_mask, /* R6 */ - arr_index, /* R7 */ - cb_logaddr, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &inv_attr_ident, /* R4 */ - &proc_mask, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall9(H_MODIFY_HEA_PORT, + outs, + adapter_handle, /* R4 */ + port_info, /* R5 */ + select_mask, /* R6 */ + arr_index, /* R7 */ + cb_logaddr, /* R8 */ + 0, 0, 0, 0); /* R9-R12 */ } u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num, const u8 reg_type, const u64 mc_mac_addr, const u16 vlan_id, const u32 hcall_id) { - u64 r5_port_num, r6_reg_type, r7_mc_mac_addr, r8_vlan_id, dummy; + u64 r5_port_num, r6_reg_type, r7_mc_mac_addr, r8_vlan_id; u64 mac_addr = mc_mac_addr >> 16; r5_port_num = EHEA_BMASK_SET(H_REGBCMC_PN, port_num); @@ -665,41 +588,21 @@ u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num, r7_mc_mac_addr = EHEA_BMASK_SET(H_REGBCMC_MACADDR, mac_addr); r8_vlan_id = EHEA_BMASK_SET(H_REGBCMC_VLANID, vlan_id); - return ehea_hcall_9arg_9ret(hcall_id, - adapter_handle, /* R4 */ - r5_port_num, /* R5 */ - r6_reg_type, /* R6 */ - r7_mc_mac_addr, /* R7 */ - r8_vlan_id, /* R8 */ - 0, 0, 0, 0, /* R9-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(hcall_id, + adapter_handle, /* R4 */ + r5_port_num, /* R5 */ + r6_reg_type, /* R6 */ + r7_mc_mac_addr, /* R7 */ + r8_vlan_id, /* R8 */ + 0, 0); /* R9-R12 */ } u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle, const u64 event_mask) { - u64 dummy; - - return ehea_hcall_9arg_9ret(H_RESET_EVENTS, - adapter_handle, /* R4 */ - neq_handle, /* R5 */ - event_mask, /* R6 */ - 0, 0, 0, 0, 0, 0, /* R7-R12 */ - &dummy, /* R4 */ - &dummy, /* R5 */ - &dummy, /* R6 */ - &dummy, /* R7 */ - &dummy, /* R8 */ - &dummy, /* R9 */ - &dummy, /* R10 */ - &dummy, /* R11 */ - &dummy); /* R12 */ + return ehea_plpar_hcall_norets(H_RESET_EVENTS, + adapter_handle, /* R4 */ + neq_handle, /* R5 */ + event_mask, /* R6 */ + 0, 0, 0, 0); /* R7-R12 */ } -- cgit v1.2.3-70-g09d2 From bff0a55f34e62970203c4af9c8ef4dc7d73e2f96 Mon Sep 17 00:00:00 2001 From: Jan-Bernd Themann Date: Thu, 5 Oct 2006 16:53:14 +0200 Subject: [PATCH] ehea: fix port state notification, default queue sizes This patch includes a bug fix for the port state notification and fixes the default queue sizes. Signed-off-by: Jan-Bernd Themann Signed-off-by: Jeff Garzik --- drivers/net/ehea/ehea.h | 13 +++++++------ drivers/net/ehea/ehea_main.c | 6 +++--- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 23b451a8ae1..b40724fc6b7 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -39,7 +39,7 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0028" +#define DRV_VERSION "EHEA_0034" #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) @@ -50,6 +50,7 @@ #define EHEA_MAX_ENTRIES_SQ 32767 #define EHEA_MIN_ENTRIES_QP 127 +#define EHEA_SMALL_QUEUES #define EHEA_NUM_TX_QP 1 #ifdef EHEA_SMALL_QUEUES @@ -59,11 +60,11 @@ #define EHEA_DEF_ENTRIES_RQ2 1023 #define EHEA_DEF_ENTRIES_RQ3 1023 #else -#define EHEA_MAX_CQE_COUNT 32000 -#define EHEA_DEF_ENTRIES_SQ 16000 -#define EHEA_DEF_ENTRIES_RQ1 32080 -#define EHEA_DEF_ENTRIES_RQ2 4020 -#define EHEA_DEF_ENTRIES_RQ3 4020 +#define EHEA_MAX_CQE_COUNT 4080 +#define EHEA_DEF_ENTRIES_SQ 4080 +#define EHEA_DEF_ENTRIES_RQ1 8160 +#define EHEA_DEF_ENTRIES_RQ2 2040 +#define EHEA_DEF_ENTRIES_RQ3 2040 #endif #define EHEA_MAX_ENTRIES_EQ 20 diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index c6b31775e26..eb7d44de59f 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -766,7 +766,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe) if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) { if (!netif_carrier_ok(port->netdev)) { ret = ehea_sense_port_attr( - adapter->port[portnum]); + port); if (ret) { ehea_error("failed resensing port " "attributes"); @@ -818,7 +818,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe) netif_stop_queue(port->netdev); break; default: - ehea_error("unknown event code %x", ec); + ehea_error("unknown event code %x, eqe=0x%lX", ec, eqe); break; } } @@ -1841,7 +1841,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) if (netif_msg_tx_queued(port)) { ehea_info("post swqe on QP %d", pr->qp->init_attr.qp_nr); - ehea_dump(swqe, sizeof(*swqe), "swqe"); + ehea_dump(swqe, 512, "swqe"); } ehea_post_swqe(pr->qp, swqe); -- cgit v1.2.3-70-g09d2 From 90f10841180e9b7938f63db69e90dacb7d21bbe5 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 15:56:04 -0500 Subject: [PATCH] powerpc/cell spidernet ethtool -i version number info. This patch adds version information as reported by ethtool -i to the Spidernet driver. From: James K Lewis Signed-off-by: James K Lewis Signed-off-by: Linas Vepstas Acked-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 3 +++ drivers/net/spider_net.h | 2 ++ drivers/net/spider_net_ethtool.c | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 46a009085f7..96dafb0f563 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -55,6 +55,7 @@ MODULE_AUTHOR("Utz Bacher and Jens Osterkamp " \ ""); MODULE_DESCRIPTION("Spider Southbridge Gigabit Ethernet driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(VERSION); static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT; static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT; @@ -2252,6 +2253,8 @@ static struct pci_driver spider_net_driver = { */ static int __init spider_net_init(void) { + printk(KERN_INFO "Spidernet version %s.\n", VERSION); + if (rx_descriptors < SPIDER_NET_RX_DESCRIPTORS_MIN) { rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MIN; pr_info("adjusting rx descriptors to %i.\n", rx_descriptors); diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index a59deda2f95..6193ea83628 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -24,6 +24,8 @@ #ifndef _SPIDER_NET_H #define _SPIDER_NET_H +#define VERSION "1.1 A" + #include "sungem_phy.h" extern int spider_net_stop(struct net_device *netdev); diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 589e43658de..fda74f7d6fd 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -76,7 +76,7 @@ spider_net_ethtool_get_drvinfo(struct net_device *netdev, /* clear and fill out info */ memset(drvinfo, 0, sizeof(struct ethtool_drvinfo)); strncpy(drvinfo->driver, spider_net_driver_name, 32); - strncpy(drvinfo->version, "0.1", 32); + strncpy(drvinfo->version, VERSION, 32); strcpy(drvinfo->fw_version, "no information"); strncpy(drvinfo->bus_info, pci_name(card->pdev), 32); } -- cgit v1.2.3-70-g09d2 From a02d601dd59d08a77563499cc05b48603df8f4a4 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 15:57:26 -0500 Subject: [PATCH] powerpc/cell spidernet burst alignment patch. This patch increases the Burst Address alignment from 64 to 1024 in the Spidernet driver. This improves transmit performance for large packets. From: James K Lewis Signed-off-by: James K Lewis Signed-off-by: Linas Vepstas Acked-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 6193ea83628..b2e3570c010 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -211,7 +211,7 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_DMA_RX_FEND_VALUE 0x00030003 /* to set TX_DMA_EN */ #define SPIDER_NET_TX_DMA_EN 0x80000000 -#define SPIDER_NET_GDTDCEIDIS 0x00000002 +#define SPIDER_NET_GDTDCEIDIS 0x00000302 #define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \ SPIDER_NET_GDTDCEIDIS #define SPIDER_NET_DMA_TX_FEND_VALUE 0x00030003 -- cgit v1.2.3-70-g09d2 From e2874f2e8c3695953b9ec26d396d678a7128ee64 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 15:59:02 -0500 Subject: [PATCH] Spidernet module parm permissions The module param permsissions should bw read-only, not writable. From: James K Lewis Signed-off-by: James K Lewis Signed-off-by: Linas Vepstas Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 96dafb0f563..ff409a10274 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -60,8 +60,8 @@ MODULE_VERSION(VERSION); static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT; static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT; -module_param(rx_descriptors, int, 0644); -module_param(tx_descriptors, int, 0644); +module_param(rx_descriptors, int, 0444); +module_param(tx_descriptors, int, 0444); MODULE_PARM_DESC(rx_descriptors, "number of descriptors used " \ "in rx chains"); -- cgit v1.2.3-70-g09d2 From c3fee4c55915c42b3278b65c91f9be8cee13426e Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:00:04 -0500 Subject: [PATCH] powerpc/cell spidernet force-end fix Bugfix: when cleaning up the transmit queue upon device close, be sure to walk the entire queue. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index ff409a10274..52bf1b2968b 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -699,6 +699,8 @@ spider_net_release_tx_descr(struct spider_net_card *card) /* unmap the skb */ skb = descr->skb; + if (!skb) + return; pci_unmap_single(card->pdev, descr->buf_addr, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); @@ -751,7 +753,8 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) default: card->netdev_stats.tx_dropped++; - return 1; + if (!brutal) + return 1; } spider_net_release_tx_descr(card); } -- cgit v1.2.3-70-g09d2 From 808999c9a4749dc67c39bf52f712d0c27aa00e67 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:01:00 -0500 Subject: [PATCH] powerpc/cell spidernet zlen min packet length Polite device drivers pad short packets to 60 bytes, so that mean-spirited users don't accidentally DOS some other OS that can't handle short packets. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 52bf1b2968b..f5f73571a7a 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -648,18 +648,26 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, { struct spider_net_descr *descr = card->tx_chain.head; dma_addr_t buf; + int length; - buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + length = skb->len; + if (length < ETH_ZLEN) { + if (skb_pad(skb, ETH_ZLEN-length)) + return 0; + length = ETH_ZLEN; + } + + buf = pci_map_single(card->pdev, skb->data, length, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(buf)) { if (netif_msg_tx_err(card) && net_ratelimit()) pr_err("could not iommu-map packet (%p, %i). " - "Dropping packet\n", skb->data, skb->len); + "Dropping packet\n", skb->data, length); card->spider_stats.tx_iommu_map_error++; return -ENOMEM; } descr->buf_addr = buf; - descr->buf_size = skb->len; + descr->buf_size = length; descr->next_descr_addr = 0; descr->skb = skb; descr->data_status = 0; @@ -693,6 +701,7 @@ spider_net_release_tx_descr(struct spider_net_card *card) { struct spider_net_descr *descr = card->tx_chain.tail; struct sk_buff *skb; + unsigned int len; card->tx_chain.tail = card->tx_chain.tail->next; descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; @@ -701,7 +710,8 @@ spider_net_release_tx_descr(struct spider_net_card *card) skb = descr->skb; if (!skb) return; - pci_unmap_single(card->pdev, descr->buf_addr, skb->len, + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + pci_unmap_single(card->pdev, descr->buf_addr, len, PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); } -- cgit v1.2.3-70-g09d2 From 917a5b8e648f420105158023ae0317eb0e77a2d5 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:01:51 -0500 Subject: [PATCH] powerpc/cell spidernet add missing netdev watchdog Set the netdev watchdog timer. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index f5f73571a7a..0aed69382b2 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -686,6 +686,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, descr->prev->next_descr_addr = descr->bus_addr; + card->netdev->trans_start = jiffies; /* set netdev watchdog timer */ return 0; } -- cgit v1.2.3-70-g09d2 From ded8028a0b61075d841c33a412da5c869140d7aa Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:02:54 -0500 Subject: [PATCH] Spidernet fix register field definitions This patch fixes the names of a few fields in the DMA control register. There is no functional change. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 2 +- drivers/net/spider_net.h | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 0aed69382b2..2f54cddf75a 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1614,7 +1614,7 @@ spider_net_enable_card(struct spider_net_card *card) SPIDER_NET_INT2_MASK_VALUE); spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR, - SPIDER_NET_GDTDCEIDIS); + SPIDER_NET_GDTBSTA | SPIDER_NET_GDTDCEIDIS); } /** diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index b2e3570c010..80f4d2739d4 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -191,7 +191,9 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_MACMODE_VALUE 0x00000001 #define SPIDER_NET_BURSTLMT_VALUE 0x00000200 /* about 16 us */ -/* 1(0) enable r/tx dma +/* DMAC control register GDMACCNTR + * + * 1(0) enable r/tx dma * 0000000 fixed to 0 * * 000000 fixed to 0 @@ -200,6 +202,7 @@ extern char spider_net_driver_name[]; * * 000000 fixed to 0 * 00 burst alignment: 128 bytes + * 11 burst alignment: 1024 bytes * * 00000 fixed to 0 * 0 descr writeback size 32 bytes @@ -210,10 +213,13 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_DMA_RX_VALUE 0x80000000 #define SPIDER_NET_DMA_RX_FEND_VALUE 0x00030003 /* to set TX_DMA_EN */ -#define SPIDER_NET_TX_DMA_EN 0x80000000 -#define SPIDER_NET_GDTDCEIDIS 0x00000302 -#define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \ - SPIDER_NET_GDTDCEIDIS +#define SPIDER_NET_TX_DMA_EN 0x80000000 +#define SPIDER_NET_GDTBSTA 0x00000300 +#define SPIDER_NET_GDTDCEIDIS 0x00000002 +#define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \ + SPIDER_NET_GDTBSTA | \ + SPIDER_NET_GDTDCEIDIS + #define SPIDER_NET_DMA_TX_FEND_VALUE 0x00030003 /* SPIDER_NET_UA_DESCR_VALUE is OR'ed with the unicast address */ -- cgit v1.2.3-70-g09d2 From 313ef4b76c96ef427a7613d89df550aa5d02bf21 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:04:00 -0500 Subject: [PATCH] Spidernet stop queue when queue is full. This patch adds a call to netif_stop_queue() when there is no more room for more packets on the transmit queue. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 2f54cddf75a..05bdd0be739 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -823,39 +823,25 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) struct spider_net_descr_chain *chain = &card->tx_chain; struct spider_net_descr *descr = chain->head; unsigned long flags; - int result; spin_lock_irqsave(&chain->lock, flags); spider_net_release_tx_chain(card, 0); - if (chain->head->next == chain->tail->prev) { - card->netdev_stats.tx_dropped++; - result = NETDEV_TX_LOCKED; - goto out; - } + if ((chain->head->next == chain->tail->prev) || + (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) || + (spider_net_prepare_tx_descr(card, skb) != 0)) { - if (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) { card->netdev_stats.tx_dropped++; - result = NETDEV_TX_LOCKED; - goto out; + spin_unlock_irqrestore(&chain->lock, flags); + netif_stop_queue(netdev); + return NETDEV_TX_BUSY; } - if (spider_net_prepare_tx_descr(card, skb) != 0) { - card->netdev_stats.tx_dropped++; - result = NETDEV_TX_BUSY; - goto out; - } - - result = NETDEV_TX_OK; - spider_net_kick_tx_dma(card); card->tx_chain.head = card->tx_chain.head->next; - -out: spin_unlock_irqrestore(&chain->lock, flags); - netif_wake_queue(netdev); - return result; + return NETDEV_TX_OK; } /** @@ -874,9 +860,10 @@ spider_net_cleanup_tx_ring(struct spider_net_card *card) spin_lock_irqsave(&card->tx_chain.lock, flags); if ((spider_net_release_tx_chain(card, 0) != 0) && - (card->netdev->flags & IFF_UP)) + (card->netdev->flags & IFF_UP)) { spider_net_kick_tx_dma(card); - + netif_wake_queue(card->netdev); + } spin_unlock_irqrestore(&card->tx_chain.lock, flags); } -- cgit v1.2.3-70-g09d2 From 43932d938d5a193bf9602b0ac8aa6783ba78b1aa Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:05:00 -0500 Subject: [PATCH] powerpc/cell spidernet bogus rx interrupt bit The current receive interrupt mask sets a bogus bit that doesn't even belong to the definition of this register. Remove it. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 80f4d2739d4..6c9d7ce7f73 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -332,9 +332,8 @@ enum spider_net_int2_status { (1 << SPIDER_NET_GDTDCEINT) | \ (1 << SPIDER_NET_GDTFDCINT) ) -/* we rely on flagged descriptor interrupts*/ -#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) | \ - (1 << SPIDER_NET_GRMFLLINT) ) +/* We rely on flagged descriptor interrupts */ +#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) ) #define SPIDER_NET_ERRINT ( 0xffffffff & \ (~SPIDER_NET_TXINT) & \ -- cgit v1.2.3-70-g09d2 From 37aad7500bf7064bf150ea1f234303f4173f7b24 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:06:53 -0500 Subject: [PATCH] powerpc/cell spidernet fix error interrupt print The print message associated with the descriptor chain end interrupt prints a bogs value. Fix that. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 05bdd0be739..9d2ed04f9fd 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1356,7 +1356,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) if (netif_msg_intr(card)) pr_err("got descriptor chain end interrupt, " "restarting DMAC %c.\n", - 'D'+i-SPIDER_NET_GDDDCEINT); + 'D'-(i-SPIDER_NET_GDDDCEINT)/3); spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); show_error = 0; -- cgit v1.2.3-70-g09d2 From 98b9040c747e50fe02ad616c9d5fee9aa4017cd1 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:08:42 -0500 Subject: [PATCH] powerpc/cell spidernet stop error printing patch. Turn off mis-interpretation of the queue-empty interrupt status bit as an error. Signed-off-by: Linas Vepstas Signed-off-by: James K Lewis Acked-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 9d2ed04f9fd..0eeff1add88 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1245,12 +1245,15 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) case SPIDER_NET_PHYINT: case SPIDER_NET_GMAC2INT: case SPIDER_NET_GMAC1INT: - case SPIDER_NET_GIPSINT: case SPIDER_NET_GFIFOINT: case SPIDER_NET_DMACINT: case SPIDER_NET_GSYSINT: break; */ + case SPIDER_NET_GIPSINT: + show_error = 0; + break; + case SPIDER_NET_GPWOPCMPINT: /* PHY write operation completed */ show_error = 0; @@ -1309,9 +1312,10 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) case SPIDER_NET_GDTDCEINT: /* chain end. If a descriptor should be sent, kick off * tx dma - if (card->tx_chain.tail == card->tx_chain.head) + if (card->tx_chain.tail != card->tx_chain.head) spider_net_kick_tx_dma(card); - show_error = 0; */ + */ + show_error = 0; break; /* case SPIDER_NET_G1TMCNTINT: not used. print a message */ @@ -1425,8 +1429,9 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) } if ((show_error) && (netif_msg_intr(card))) - pr_err("Got error interrupt, GHIINT0STS = 0x%08x, " + pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, " "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n", + card->netdev->name, status_reg, error_reg1, error_reg2); /* clear interrupt sources */ -- cgit v1.2.3-70-g09d2 From b21606a773faffc2b3ec326325c433bdf37ecbdf Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:09:40 -0500 Subject: [PATCH] powerpc/cell spidernet incorrect offset Bugfix -- the rx chain is in memory after the tx chain -- the offset being used was wrong, resulting in memory corruption when the size of the rx and tx rings weren't exactly the same. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 0eeff1add88..d779a0b9d45 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1628,8 +1628,10 @@ spider_net_open(struct net_device *netdev) if (spider_net_init_chain(card, &card->tx_chain, card->descr, PCI_DMA_TODEVICE, card->tx_desc)) goto alloc_tx_failed; + + /* rx_chain is after tx_chain, so offset is descr + tx_count */ if (spider_net_init_chain(card, &card->rx_chain, - card->descr + card->rx_desc, + card->descr + card->tx_desc, PCI_DMA_FROMDEVICE, card->rx_desc)) goto alloc_rx_failed; -- cgit v1.2.3-70-g09d2 From 204e5fa17c7ba45a89989f8da6dfe8e54d64b79b Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:11:33 -0500 Subject: [PATCH] powerpc/cell spidernet low watermark patch. Implement basic low-watermark support for the transmit queue. Hardware low-watermarks allow a properly configured kernel to continously stream data to a device and not have to handle any interrupts at all in doing so. Correct zero-interrupt operation can be actually observed for this driver, when the socket buffer is made large enough. The basic idea of a low-watermark interrupt is as follows. The device driver queues up a bunch of packets for the hardware to transmit, and then kicks the hardware to get it started. As the hardware drains the queue of pending, untransmitted packets, the device driver will want to know when the queue is almost empty, so that it can queue some more packets. If the queue drains down to the low waterark, then an interrupt will be generated. However, if the kernel/driver continues to add enough packets to keep the queue partially filled, no interrupt will actually be generated, and the hardware can continue streaming packets indefinitely in this mode. The impelmentation is done by setting the DESCR_TXDESFLG flag in one of the packets. When the hardware sees this flag, it will interrupt the device driver. Because this flag is on a fixed packet, rather than at fixed location in the queue, the code below needs to move the flag as more packets are queued up. This implementation attempts to keep the flag at about 1/4 from "empty". Signed-off-by: Linas Vepstas Signed-off-by: James K Lewis Acked-by: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 43 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/spider_net.h | 8 ++++---- 2 files changed, 47 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index d779a0b9d45..96b5d00c21d 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -684,6 +684,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, break; } + /* Chain the bus address, so that the DMA engine finds this descr. */ descr->prev->next_descr_addr = descr->bus_addr; card->netdev->trans_start = jiffies; /* set netdev watchdog timer */ @@ -717,6 +718,41 @@ spider_net_release_tx_descr(struct spider_net_card *card) dev_kfree_skb_any(skb); } +static void +spider_net_set_low_watermark(struct spider_net_card *card) +{ + int status; + int cnt=0; + int i; + struct spider_net_descr *descr = card->tx_chain.tail; + + /* Measure the length of the queue. */ + while (descr != card->tx_chain.head) { + status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE; + if (status == SPIDER_NET_DESCR_NOT_IN_USE) + break; + descr = descr->next; + cnt++; + } + + /* If TX queue is short, don't even bother with interrupts */ + if (cnt < card->tx_desc/4) + return; + + /* Set low-watermark 3/4th's of the way into the queue. */ + descr = card->tx_chain.tail; + cnt = (cnt*3)/4; + for (i=0;inext; + + /* Set the new watermark, clear the old watermark */ + descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG; + if (card->low_watermark && card->low_watermark != descr) + card->low_watermark->dmac_cmd_status = + card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG; + card->low_watermark = descr; +} + /** * spider_net_release_tx_chain - processes sent tx descriptors * @card: adapter structure @@ -838,6 +874,7 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_BUSY; } + spider_net_set_low_watermark(card); spider_net_kick_tx_dma(card); card->tx_chain.head = card->tx_chain.head->next; spin_unlock_irqrestore(&chain->lock, flags); @@ -1467,6 +1504,10 @@ spider_net_interrupt(int irq, void *ptr) spider_net_rx_irq_off(card); netif_rx_schedule(netdev); } + if (status_reg & SPIDER_NET_TXINT ) { + spider_net_cleanup_tx_ring(card); + netif_wake_queue(netdev); + } if (status_reg & SPIDER_NET_ERRINT ) spider_net_handle_error_irq(card, status_reg); @@ -1629,6 +1670,8 @@ spider_net_open(struct net_device *netdev) PCI_DMA_TODEVICE, card->tx_desc)) goto alloc_tx_failed; + card->low_watermark = NULL; + /* rx_chain is after tx_chain, so offset is descr + tx_count */ if (spider_net_init_chain(card, &card->rx_chain, card->descr + card->tx_desc, diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 6c9d7ce7f73..1f5c9dc806a 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -49,7 +49,7 @@ extern char spider_net_driver_name[]; #define SPIDER_NET_TX_DESCRIPTORS_MIN 16 #define SPIDER_NET_TX_DESCRIPTORS_MAX 512 -#define SPIDER_NET_TX_TIMER 20 +#define SPIDER_NET_TX_TIMER (HZ/5) #define SPIDER_NET_RX_CSUM_DEFAULT 1 @@ -328,9 +328,7 @@ enum spider_net_int2_status { SPIDER_NET_GRISPDNGINT }; -#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GTTEDINT) | \ - (1 << SPIDER_NET_GDTDCEINT) | \ - (1 << SPIDER_NET_GDTFDCINT) ) +#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GDTFDCINT) ) /* We rely on flagged descriptor interrupts */ #define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) ) @@ -356,6 +354,7 @@ enum spider_net_int2_status { #define SPIDER_NET_DESCR_FORCE_END 0x50000000 /* used in rx and tx */ #define SPIDER_NET_DESCR_CARDOWNED 0xA0000000 /* used in rx and tx */ #define SPIDER_NET_DESCR_NOT_IN_USE 0xF0000000 +#define SPIDER_NET_DESCR_TXDESFLG 0x00800000 struct spider_net_descr { /* as defined by the hardware */ @@ -440,6 +439,7 @@ struct spider_net_card { struct spider_net_descr_chain tx_chain; struct spider_net_descr_chain rx_chain; + struct spider_net_descr *low_watermark; struct net_device_stats netdev_stats; -- cgit v1.2.3-70-g09d2 From 68a8c609b3071c2441fa64f584d15311f2c10e61 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:13:05 -0500 Subject: [PATCH] powerpc/cell spidernet NAPI polling info. This patch moves transmit queue cleanup code out of the interrupt context, and into the NAPI polling routine. Signed-off-by: Linas Vepstas Acked-by: Arnd Bergmann Cc: James K Lewis Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 96b5d00c21d..e429abc1e94 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -715,7 +715,7 @@ spider_net_release_tx_descr(struct spider_net_card *card) len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; pci_unmap_single(card->pdev, descr->buf_addr, len, PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); } static void @@ -885,9 +885,10 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) * spider_net_cleanup_tx_ring - cleans up the TX ring * @card: card structure * - * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use - * interrupts to cleanup our TX ring) and returns sent packets to the stack - * by freeing them + * spider_net_cleanup_tx_ring is called by either the tx_timer + * or from the NAPI polling routine. + * This routine releases resources associted with transmitted + * packets, including updating the queue tail pointer. */ static void spider_net_cleanup_tx_ring(struct spider_net_card *card) @@ -1092,6 +1093,7 @@ spider_net_poll(struct net_device *netdev, int *budget) int packets_to_do, packets_done = 0; int no_more_packets = 0; + spider_net_cleanup_tx_ring(card); packets_to_do = min(*budget, netdev->quota); while (packets_to_do) { @@ -1504,10 +1506,8 @@ spider_net_interrupt(int irq, void *ptr) spider_net_rx_irq_off(card); netif_rx_schedule(netdev); } - if (status_reg & SPIDER_NET_TXINT ) { - spider_net_cleanup_tx_ring(card); - netif_wake_queue(netdev); - } + if (status_reg & SPIDER_NET_TXINT) + netif_rx_schedule(netdev); if (status_reg & SPIDER_NET_ERRINT ) spider_net_handle_error_irq(card, status_reg); -- cgit v1.2.3-70-g09d2 From 9cc7bf7edf50a8a6b456b337aff97fe780ae369b Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:14:29 -0500 Subject: [PATCH] powerpc/cell spidernet refine locking The transmit side of the spider ethernet driver currently places locks around some very large chunks of code. This results in a fair amount of lock contention is some cases. This patch makes the locks much more fine-grained, protecting only the cirtical sections. One lock is used to protect three locations: the queue head and tail pointers, and the queue low-watermark location. Signed-off-by: Linas Vepstas Cc: Arnd Bergmann Cc: James K Lewis Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 95 ++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index e429abc1e94..f8d7d0d91a6 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -646,8 +646,9 @@ static int spider_net_prepare_tx_descr(struct spider_net_card *card, struct sk_buff *skb) { - struct spider_net_descr *descr = card->tx_chain.head; + struct spider_net_descr *descr; dma_addr_t buf; + unsigned long flags; int length; length = skb->len; @@ -666,6 +667,10 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, return -ENOMEM; } + spin_lock_irqsave(&card->tx_chain.lock, flags); + descr = card->tx_chain.head; + card->tx_chain.head = descr->next; + descr->buf_addr = buf; descr->buf_size = length; descr->next_descr_addr = 0; @@ -674,6 +679,8 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS; + spin_unlock_irqrestore(&card->tx_chain.lock, flags); + if (skb->protocol == htons(ETH_P_IP)) switch (skb->nh.iph->protocol) { case IPPROTO_TCP: @@ -691,42 +698,17 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, return 0; } -/** - * spider_net_release_tx_descr - processes a used tx descriptor - * @card: card structure - * @descr: descriptor to release - * - * releases a used tx descriptor (unmapping, freeing of skb) - */ -static inline void -spider_net_release_tx_descr(struct spider_net_card *card) -{ - struct spider_net_descr *descr = card->tx_chain.tail; - struct sk_buff *skb; - unsigned int len; - - card->tx_chain.tail = card->tx_chain.tail->next; - descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; - - /* unmap the skb */ - skb = descr->skb; - if (!skb) - return; - len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; - pci_unmap_single(card->pdev, descr->buf_addr, len, - PCI_DMA_TODEVICE); - dev_kfree_skb(skb); -} - static void spider_net_set_low_watermark(struct spider_net_card *card) { + unsigned long flags; int status; int cnt=0; int i; struct spider_net_descr *descr = card->tx_chain.tail; - /* Measure the length of the queue. */ + /* Measure the length of the queue. Measurement does not + * need to be precise -- does not need a lock. */ while (descr != card->tx_chain.head) { status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE; if (status == SPIDER_NET_DESCR_NOT_IN_USE) @@ -746,11 +728,13 @@ spider_net_set_low_watermark(struct spider_net_card *card) descr = descr->next; /* Set the new watermark, clear the old watermark */ + spin_lock_irqsave(&card->tx_chain.lock, flags); descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG; if (card->low_watermark && card->low_watermark != descr) card->low_watermark->dmac_cmd_status = card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG; card->low_watermark = descr; + spin_unlock_irqrestore(&card->tx_chain.lock, flags); } /** @@ -769,21 +753,31 @@ static int spider_net_release_tx_chain(struct spider_net_card *card, int brutal) { struct spider_net_descr_chain *chain = &card->tx_chain; + struct spider_net_descr *descr; + struct sk_buff *skb; + u32 buf_addr; + unsigned long flags; int status; spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR); while (chain->tail != chain->head) { - status = spider_net_get_descr_status(chain->tail); + spin_lock_irqsave(&chain->lock, flags); + descr = chain->tail; + + status = spider_net_get_descr_status(descr); switch (status) { case SPIDER_NET_DESCR_COMPLETE: card->netdev_stats.tx_packets++; - card->netdev_stats.tx_bytes += chain->tail->skb->len; + card->netdev_stats.tx_bytes += descr->skb->len; break; case SPIDER_NET_DESCR_CARDOWNED: - if (!brutal) + if (!brutal) { + spin_unlock_irqrestore(&chain->lock, flags); return 1; + } + /* fallthrough, if we release the descriptors * brutally (then we don't care about * SPIDER_NET_DESCR_CARDOWNED) */ @@ -800,12 +794,25 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) default: card->netdev_stats.tx_dropped++; - if (!brutal) + if (!brutal) { + spin_unlock_irqrestore(&chain->lock, flags); return 1; + } } - spider_net_release_tx_descr(card); - } + chain->tail = descr->next; + descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; + skb = descr->skb; + buf_addr = descr->buf_addr; + spin_unlock_irqrestore(&chain->lock, flags); + + /* unmap the skb */ + if (skb) { + int len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + pci_unmap_single(card->pdev, buf_addr, len, PCI_DMA_TODEVICE); + dev_kfree_skb(skb); + } + } return 0; } @@ -857,27 +864,19 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); struct spider_net_descr_chain *chain = &card->tx_chain; - struct spider_net_descr *descr = chain->head; - unsigned long flags; - - spin_lock_irqsave(&chain->lock, flags); spider_net_release_tx_chain(card, 0); if ((chain->head->next == chain->tail->prev) || - (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) || (spider_net_prepare_tx_descr(card, skb) != 0)) { card->netdev_stats.tx_dropped++; - spin_unlock_irqrestore(&chain->lock, flags); netif_stop_queue(netdev); return NETDEV_TX_BUSY; } spider_net_set_low_watermark(card); spider_net_kick_tx_dma(card); - card->tx_chain.head = card->tx_chain.head->next; - spin_unlock_irqrestore(&chain->lock, flags); return NETDEV_TX_OK; } @@ -893,16 +892,11 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) static void spider_net_cleanup_tx_ring(struct spider_net_card *card) { - unsigned long flags; - - spin_lock_irqsave(&card->tx_chain.lock, flags); - if ((spider_net_release_tx_chain(card, 0) != 0) && (card->netdev->flags & IFF_UP)) { spider_net_kick_tx_dma(card); netif_wake_queue(card->netdev); } - spin_unlock_irqrestore(&card->tx_chain.lock, flags); } /** @@ -1930,10 +1924,7 @@ spider_net_stop(struct net_device *netdev) spider_net_disable_rxdmac(card); /* release chains */ - if (spin_trylock(&card->tx_chain.lock)) { - spider_net_release_tx_chain(card, 1); - spin_unlock(&card->tx_chain.lock); - } + spider_net_release_tx_chain(card, 1); spider_net_free_chain(card, &card->tx_chain); spider_net_free_chain(card, &card->rx_chain); -- cgit v1.2.3-70-g09d2 From 499eea18722e43f0ee15e11ac16ffcbd10b70b24 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:15:29 -0500 Subject: [PATCH] powerpc/cell spidernet Remove a dummy register read that is not needed. This reduces CPU usage notably during transmit. Signed-off-by: Linas Vepstas Cc: Arnd Bergmann Cc: James K Lewis Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index f8d7d0d91a6..6bb8f1f9437 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -759,8 +759,6 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) unsigned long flags; int status; - spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR); - while (chain->tail != chain->head) { spin_lock_irqsave(&chain->lock, flags); descr = chain->tail; -- cgit v1.2.3-70-g09d2 From a664ccf430547696951bf3949f5a2de5079ece5a Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:18:18 -0500 Subject: [PATCH] powerpc/cell spidernet reduce DMA kicking The current code attempts to start the TX dma every time a packet is queued. This is too conservative, and wastes CPU time. This patch changes behaviour to call the kick-dma function less often, only when the tx queue is at risk of emptying. This reduces cpu usage, improves performance. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 6bb8f1f9437..caa11c6f21b 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -698,7 +698,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, return 0; } -static void +static int spider_net_set_low_watermark(struct spider_net_card *card) { unsigned long flags; @@ -719,7 +719,7 @@ spider_net_set_low_watermark(struct spider_net_card *card) /* If TX queue is short, don't even bother with interrupts */ if (cnt < card->tx_desc/4) - return; + return cnt; /* Set low-watermark 3/4th's of the way into the queue. */ descr = card->tx_chain.tail; @@ -735,6 +735,7 @@ spider_net_set_low_watermark(struct spider_net_card *card) card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG; card->low_watermark = descr; spin_unlock_irqrestore(&card->tx_chain.lock, flags); + return cnt; } /** @@ -819,8 +820,12 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) * @card: card structure * @descr: descriptor address to enable TX processing at * - * spider_net_kick_tx_dma writes the current tx chain head as start address - * of the tx descriptor chain and enables the transmission DMA engine + * This routine will start the transmit DMA running if + * it is not already running. This routine ned only be + * called when queueing a new packet to an empty tx queue. + * Writes the current tx chain head as start address + * of the tx descriptor chain and enables the transmission + * DMA engine. */ static inline void spider_net_kick_tx_dma(struct spider_net_card *card) @@ -860,6 +865,7 @@ out: static int spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) { + int cnt; struct spider_net_card *card = netdev_priv(netdev); struct spider_net_descr_chain *chain = &card->tx_chain; @@ -873,8 +879,9 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_BUSY; } - spider_net_set_low_watermark(card); - spider_net_kick_tx_dma(card); + cnt = spider_net_set_low_watermark(card); + if (cnt < 5) + spider_net_kick_tx_dma(card); return NETDEV_TX_OK; } -- cgit v1.2.3-70-g09d2 From 66c097165cf6d4196e798145fb33c768164fb361 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:19:34 -0500 Subject: [PATCH] powerpc/cell spidernet variable name change Cosmetic patch: give the variable holding the numer of descriptors a more descriptive name, so to avoid confusion. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 12 ++++++------ drivers/net/spider_net.h | 4 ++-- drivers/net/spider_net_ethtool.c | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index caa11c6f21b..88e7e41adec 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -718,7 +718,7 @@ spider_net_set_low_watermark(struct spider_net_card *card) } /* If TX queue is short, don't even bother with interrupts */ - if (cnt < card->tx_desc/4) + if (cnt < card->num_tx_desc/4) return cnt; /* Set low-watermark 3/4th's of the way into the queue. */ @@ -1666,15 +1666,15 @@ spider_net_open(struct net_device *netdev) result = -ENOMEM; if (spider_net_init_chain(card, &card->tx_chain, card->descr, - PCI_DMA_TODEVICE, card->tx_desc)) + PCI_DMA_TODEVICE, card->num_tx_desc)) goto alloc_tx_failed; card->low_watermark = NULL; /* rx_chain is after tx_chain, so offset is descr + tx_count */ if (spider_net_init_chain(card, &card->rx_chain, - card->descr + card->tx_desc, - PCI_DMA_FROMDEVICE, card->rx_desc)) + card->descr + card->num_tx_desc, + PCI_DMA_FROMDEVICE, card->num_rx_desc)) goto alloc_rx_failed; /* allocate rx skbs */ @@ -2060,8 +2060,8 @@ spider_net_setup_netdev(struct spider_net_card *card) card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT; - card->tx_desc = tx_descriptors; - card->rx_desc = rx_descriptors; + card->num_tx_desc = tx_descriptors; + card->num_rx_desc = rx_descriptors; spider_net_setup_netdev_ops(netdev); diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 1f5c9dc806a..b3b46119b42 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h @@ -455,8 +455,8 @@ struct spider_net_card { /* for ethtool */ int msg_enable; - int rx_desc; - int tx_desc; + int num_rx_desc; + int num_tx_desc; struct spider_net_extra_stats spider_stats; struct spider_net_descr descr[0]; diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index fda74f7d6fd..91b99510291 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -158,9 +158,9 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev, struct spider_net_card *card = netdev->priv; ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX; - ering->tx_pending = card->tx_desc; + ering->tx_pending = card->num_tx_desc; ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX; - ering->rx_pending = card->rx_desc; + ering->rx_pending = card->num_rx_desc; } static int spider_net_get_stats_count(struct net_device *netdev) -- cgit v1.2.3-70-g09d2 From 348bc2a6e306dc3e875cee3389e1405963ace617 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:21:10 -0500 Subject: [PATCH] powerpc/cell spidernet DMA direction fix The ring buffer descriptors are DMA-accessed bidirectionally, but are not declared in this way. Fix this. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 88e7e41adec..a26dd1c6318 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -301,7 +301,7 @@ static int spider_net_init_chain(struct spider_net_card *card, struct spider_net_descr_chain *chain, struct spider_net_descr *start_descr, - int direction, int no) + int no) { int i; struct spider_net_descr *descr; @@ -316,7 +316,7 @@ spider_net_init_chain(struct spider_net_card *card, buf = pci_map_single(card->pdev, descr, SPIDER_NET_DESCR_SIZE, - direction); + PCI_DMA_BIDIRECTIONAL); if (pci_dma_mapping_error(buf)) goto iommu_error; @@ -330,11 +330,6 @@ spider_net_init_chain(struct spider_net_card *card, (descr-1)->next = start_descr; start_descr->prev = descr-1; - descr = start_descr; - if (direction == PCI_DMA_FROMDEVICE) - for (i=0; i < no; i++, descr++) - descr->next_descr_addr = descr->next->bus_addr; - spin_lock_init(&chain->lock); chain->head = start_descr; chain->tail = start_descr; @@ -347,7 +342,7 @@ iommu_error: if (descr->bus_addr) pci_unmap_single(card->pdev, descr->bus_addr, SPIDER_NET_DESCR_SIZE, - direction); + PCI_DMA_BIDIRECTIONAL); return -ENOMEM; } @@ -368,7 +363,7 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) dev_kfree_skb(descr->skb); pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME, - PCI_DMA_FROMDEVICE); + PCI_DMA_BIDIRECTIONAL); } descr = descr->next; } @@ -1662,21 +1657,26 @@ int spider_net_open(struct net_device *netdev) { struct spider_net_card *card = netdev_priv(netdev); - int result; + struct spider_net_descr *descr; + int i, result; result = -ENOMEM; if (spider_net_init_chain(card, &card->tx_chain, card->descr, - PCI_DMA_TODEVICE, card->num_tx_desc)) + card->num_tx_desc)) goto alloc_tx_failed; card->low_watermark = NULL; /* rx_chain is after tx_chain, so offset is descr + tx_count */ if (spider_net_init_chain(card, &card->rx_chain, - card->descr + card->num_tx_desc, - PCI_DMA_FROMDEVICE, card->num_rx_desc)) + card->descr + card->num_tx_desc, + card->num_rx_desc)) goto alloc_rx_failed; + descr = card->rx_chain.head; + for (i=0; i < card->num_rx_desc; i++, descr++) + descr->next_descr_addr = descr->next->bus_addr; + /* allocate rx skbs */ if (spider_net_alloc_rx_skbs(card)) goto alloc_skbs_failed; -- cgit v1.2.3-70-g09d2 From 647519100105fb4ddfe6455e820093999c08c4be Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 10 Oct 2006 16:22:29 -0500 Subject: [PATCH] powerpc/cell spidernet release all descrs Bugfix: rx descriptor release function fails to visit the last entry while walking receive descriptor ring. Signed-off-by: Linas Vepstas Cc: James K Lewis Cc: Arnd Bergmann Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index a26dd1c6318..418138dd6c6 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -358,7 +358,7 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) struct spider_net_descr *descr; descr = card->rx_chain.head; - while (descr->next != card->rx_chain.head) { + do { if (descr->skb) { dev_kfree_skb(descr->skb); pci_unmap_single(card->pdev, descr->buf_addr, @@ -366,7 +366,7 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) PCI_DMA_BIDIRECTIONAL); } descr = descr->next; - } + } while (descr != card->rx_chain.head); } /** -- cgit v1.2.3-70-g09d2 From a1bc9b875be597cdf147db2748ba7ddc6b0f0fbe Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Oct 2006 15:49:50 -0700 Subject: [PATCH] skge: fix stuck irq when fiber down The PHY interrupt from the internal fiber is getting stuck on when the link is down. Add code to handle the transition and mask it. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 53 +++++++++++++++++++++++++++++++++++------------------ drivers/net/skge.h | 3 ++- 2 files changed, 37 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index a4a58e4e93a..57764935a9f 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -884,6 +884,29 @@ static void skge_link_down(struct skge_port *skge) printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name); } + +static void xm_link_down(struct skge_hw *hw, int port) +{ + struct net_device *dev = hw->dev[port]; + struct skge_port *skge = netdev_priv(dev); + u16 cmd, msk; + + if (hw->phy_type == SK_PHY_XMAC) { + msk = xm_read16(hw, port, XM_IMSK); + msk |= XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND; + xm_write16(hw, port, XM_IMSK, msk); + } + + cmd = xm_read16(hw, port, XM_MMU_CMD); + cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); + xm_write16(hw, port, XM_MMU_CMD, cmd); + /* dummy read to ensure writing */ + (void) xm_read16(hw, port, XM_MMU_CMD); + + if (netif_carrier_ok(dev)) + skge_link_down(skge); +} + static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val) { int i; @@ -1008,14 +1031,7 @@ static void bcom_check_link(struct skge_hw *hw, int port) status = xm_phy_read(hw, port, PHY_BCOM_STAT); if ((status & PHY_ST_LSYNC) == 0) { - u16 cmd = xm_read16(hw, port, XM_MMU_CMD); - cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); - xm_write16(hw, port, XM_MMU_CMD, cmd); - /* dummy read to ensure writing */ - (void) xm_read16(hw, port, XM_MMU_CMD); - - if (netif_carrier_ok(dev)) - skge_link_down(skge); + xm_link_down(hw, port); return; } @@ -1235,14 +1251,7 @@ static void xm_check_link(struct net_device *dev) status = xm_phy_read(hw, port, PHY_XMAC_STAT); if ((status & PHY_ST_LSYNC) == 0) { - u16 cmd = xm_read16(hw, port, XM_MMU_CMD); - cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX); - xm_write16(hw, port, XM_MMU_CMD, cmd); - /* dummy read to ensure writing */ - (void) xm_read16(hw, port, XM_MMU_CMD); - - if (netif_carrier_ok(dev)) - skge_link_down(skge); + xm_link_down(hw, port); return; } @@ -1568,6 +1577,10 @@ static void genesis_mac_intr(struct skge_hw *hw, int port) printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n", skge->netdev->name, status); + if (hw->phy_type == SK_PHY_XMAC && + (status & (XM_IS_INP_ASS | XM_IS_LIPA_RC))) + xm_link_down(hw, port); + if (status & XM_IS_TXF_UR) { xm_write32(hw, port, XM_MODE, XM_MD_FTF); ++skge->net_stats.tx_fifo_errors; @@ -1582,7 +1595,7 @@ static void genesis_link_up(struct skge_port *skge) { struct skge_hw *hw = skge->hw; int port = skge->port; - u16 cmd; + u16 cmd, msk; u32 mode; cmd = xm_read16(hw, port, XM_MMU_CMD); @@ -1631,7 +1644,11 @@ static void genesis_link_up(struct skge_port *skge) } xm_write32(hw, port, XM_MODE, mode); - xm_write16(hw, port, XM_IMSK, XM_DEF_MSK); + msk = XM_DEF_MSK; + if (hw->phy_type != SK_PHY_XMAC) + msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */ + + xm_write16(hw, port, XM_IMSK, msk); xm_read16(hw, port, XM_ISRC); /* get MMU Command Reg. */ diff --git a/drivers/net/skge.h b/drivers/net/skge.h index d0b47d46cf9..9cc955c1250 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2195,7 +2195,8 @@ enum { XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */ }; -#define XM_DEF_MSK (~(XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_RXF_OV | XM_IS_TXF_UR)) +#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | \ + XM_IS_RXF_OV | XM_IS_TXF_UR)) /* XM_HW_CFG 16 bit r/w Hardware Config Register */ -- cgit v1.2.3-70-g09d2 From 4b67be999ed5bfb1bfe4cc502d37d59b4f6b6b7f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Oct 2006 15:49:51 -0700 Subject: [PATCH] skge: pause mapping for fiber Do correct mapping of pause and duplex when using 1000BaseX fiber versions of the board. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 57764935a9f..c19f49bce7a 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -197,8 +197,8 @@ static u32 skge_supported_modes(const struct skge_hw *hw) else if (hw->chip_id == CHIP_ID_YUKON) supported &= ~SUPPORTED_1000baseT_Half; } else - supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE - | SUPPORTED_Autoneg; + supported = SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half + | SUPPORTED_FIBRE | SUPPORTED_Autoneg; return supported; } @@ -1018,6 +1018,14 @@ static const u16 phy_pause_map[] = { [FLOW_MODE_REM_SEND] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, }; +/* special defines for FIBER (88E1011S only) */ +static const u16 fiber_pause_map[] = { + [FLOW_MODE_NONE] = PHY_X_P_NO_PAUSE, + [FLOW_MODE_LOC_SEND] = PHY_X_P_ASYM_MD, + [FLOW_MODE_SYMMETRIC] = PHY_X_P_SYM_MD, + [FLOW_MODE_REM_SEND] = PHY_X_P_BOTH_MD, +}; + /* Check status of Broadcom phy link */ static void bcom_check_link(struct skge_hw *hw, int port) @@ -1207,17 +1215,7 @@ static void xm_phy_init(struct skge_port *skge) if (skge->advertising & ADVERTISED_1000baseT_Full) ctrl |= PHY_X_AN_FD; - switch(skge->flow_control) { - case FLOW_MODE_NONE: - ctrl |= PHY_X_P_NO_PAUSE; - break; - case FLOW_MODE_LOC_SEND: - ctrl |= PHY_X_P_ASYM_MD; - break; - case FLOW_MODE_SYMMETRIC: - ctrl |= PHY_X_P_BOTH_MD; - break; - } + ctrl |= fiber_pause_map[skge->flow_control]; xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl); @@ -1796,11 +1794,17 @@ static void yukon_init(struct skge_hw *hw, int port) adv |= PHY_M_AN_10_FD; if (skge->advertising & ADVERTISED_10baseT_Half) adv |= PHY_M_AN_10_HD; - } else /* special defines for FIBER (88E1011S only) */ - adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD; - /* Set Flow-control capabilities */ - adv |= phy_pause_map[skge->flow_control]; + /* Set Flow-control capabilities */ + adv |= phy_pause_map[skge->flow_control]; + } else { + if (skge->advertising & ADVERTISED_1000baseT_Full) + adv |= PHY_M_AN_1000X_AFD; + if (skge->advertising & ADVERTISED_1000baseT_Half) + adv |= PHY_M_AN_1000X_AHD; + + adv |= fiber_pause_map[skge->flow_control]; + } /* Restart Auto-negotiation */ ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG; -- cgit v1.2.3-70-g09d2 From 5d5c8e03786691d0d083142b922edce8609c0fd5 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Oct 2006 15:49:52 -0700 Subject: [PATCH] skge: better flow control negotiation Do flow control negotiation properly. Don't let auto negotiation status limit renegotiation. Separate desired pause values from the result of auto negotiation. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 129 ++++++++++++++++++++++++++++++++--------------------- drivers/net/skge.h | 22 ++++++--- 2 files changed, 95 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index c19f49bce7a..d844a837a8f 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -487,31 +487,37 @@ static void skge_get_pauseparam(struct net_device *dev, { struct skge_port *skge = netdev_priv(dev); - ecmd->tx_pause = (skge->flow_control == FLOW_MODE_LOC_SEND) - || (skge->flow_control == FLOW_MODE_SYMMETRIC); - ecmd->rx_pause = (skge->flow_control == FLOW_MODE_REM_SEND) - || (skge->flow_control == FLOW_MODE_SYMMETRIC); + ecmd->rx_pause = (skge->flow_control == FLOW_MODE_SYMMETRIC) + || (skge->flow_control == FLOW_MODE_SYM_OR_REM); + ecmd->tx_pause = ecmd->rx_pause || (skge->flow_control == FLOW_MODE_LOC_SEND); - ecmd->autoneg = skge->autoneg; + ecmd->autoneg = ecmd->rx_pause || ecmd->tx_pause; } static int skge_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *ecmd) { struct skge_port *skge = netdev_priv(dev); + struct ethtool_pauseparam old; - skge->autoneg = ecmd->autoneg; - if (ecmd->rx_pause && ecmd->tx_pause) - skge->flow_control = FLOW_MODE_SYMMETRIC; - else if (ecmd->rx_pause && !ecmd->tx_pause) - skge->flow_control = FLOW_MODE_REM_SEND; - else if (!ecmd->rx_pause && ecmd->tx_pause) - skge->flow_control = FLOW_MODE_LOC_SEND; - else - skge->flow_control = FLOW_MODE_NONE; + skge_get_pauseparam(dev, &old); + + if (ecmd->autoneg != old.autoneg) + skge->flow_control = ecmd->autoneg ? FLOW_MODE_NONE : FLOW_MODE_SYMMETRIC; + else { + if (ecmd->rx_pause && ecmd->tx_pause) + skge->flow_control = FLOW_MODE_SYMMETRIC; + else if (ecmd->rx_pause && !ecmd->tx_pause) + skge->flow_control = FLOW_MODE_SYM_OR_REM; + else if (!ecmd->rx_pause && ecmd->tx_pause) + skge->flow_control = FLOW_MODE_LOC_SEND; + else + skge->flow_control = FLOW_MODE_NONE; + } if (netif_running(dev)) skge_phy_reset(skge); + return 0; } @@ -854,6 +860,23 @@ static int skge_rx_fill(struct net_device *dev) return 0; } +static const char *skge_pause(enum pause_status status) +{ + switch(status) { + case FLOW_STAT_NONE: + return "none"; + case FLOW_STAT_REM_SEND: + return "rx only"; + case FLOW_STAT_LOC_SEND: + return "tx_only"; + case FLOW_STAT_SYMMETRIC: /* Both station may send PAUSE */ + return "both"; + default: + return "indeterminated"; + } +} + + static void skge_link_up(struct skge_port *skge) { skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), @@ -862,16 +885,13 @@ static void skge_link_up(struct skge_port *skge) netif_carrier_on(skge->netdev); netif_wake_queue(skge->netdev); - if (netif_msg_link(skge)) + if (netif_msg_link(skge)) { printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex, flow control %s\n", skge->netdev->name, skge->speed, skge->duplex == DUPLEX_FULL ? "full" : "half", - (skge->flow_control == FLOW_MODE_NONE) ? "none" : - (skge->flow_control == FLOW_MODE_LOC_SEND) ? "tx only" : - (skge->flow_control == FLOW_MODE_REM_SEND) ? "rx only" : - (skge->flow_control == FLOW_MODE_SYMMETRIC) ? "tx and rx" : - "unknown"); + skge_pause(skge->flow_status)); + } } static void skge_link_down(struct skge_port *skge) @@ -1015,7 +1035,7 @@ static const u16 phy_pause_map[] = { [FLOW_MODE_NONE] = 0, [FLOW_MODE_LOC_SEND] = PHY_AN_PAUSE_ASYM, [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP, - [FLOW_MODE_REM_SEND] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, + [FLOW_MODE_SYM_OR_REM] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM, }; /* special defines for FIBER (88E1011S only) */ @@ -1023,7 +1043,7 @@ static const u16 fiber_pause_map[] = { [FLOW_MODE_NONE] = PHY_X_P_NO_PAUSE, [FLOW_MODE_LOC_SEND] = PHY_X_P_ASYM_MD, [FLOW_MODE_SYMMETRIC] = PHY_X_P_SYM_MD, - [FLOW_MODE_REM_SEND] = PHY_X_P_BOTH_MD, + [FLOW_MODE_SYM_OR_REM] = PHY_X_P_BOTH_MD, }; @@ -1072,20 +1092,19 @@ static void bcom_check_link(struct skge_hw *hw, int port) return; } - /* We are using IEEE 802.3z/D5.0 Table 37-4 */ switch (aux & PHY_B_AS_PAUSE_MSK) { case PHY_B_AS_PAUSE_MSK: - skge->flow_control = FLOW_MODE_SYMMETRIC; + skge->flow_status = FLOW_STAT_SYMMETRIC; break; case PHY_B_AS_PRR: - skge->flow_control = FLOW_MODE_REM_SEND; + skge->flow_status = FLOW_STAT_REM_SEND; break; case PHY_B_AS_PRT: - skge->flow_control = FLOW_MODE_LOC_SEND; + skge->flow_status = FLOW_STAT_LOC_SEND; break; default: - skge->flow_control = FLOW_MODE_NONE; + skge->flow_status = FLOW_STAT_NONE; } skge->speed = SPEED_1000; } @@ -1283,15 +1302,20 @@ static void xm_check_link(struct net_device *dev) } /* We are using IEEE 802.3z/D5.0 Table 37-4 */ - if (lpa & PHY_X_P_SYM_MD) - skge->flow_control = FLOW_MODE_SYMMETRIC; - else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) - skge->flow_control = FLOW_MODE_REM_SEND; - else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) - skge->flow_control = FLOW_MODE_LOC_SEND; + if ((skge->flow_control == FLOW_MODE_SYMMETRIC || + skge->flow_control == FLOW_MODE_SYM_OR_REM) && + (lpa & PHY_X_P_SYM_MD)) + skge->flow_status = FLOW_STAT_SYMMETRIC; + else if (skge->flow_control == FLOW_MODE_SYM_OR_REM && + (lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD) + /* Enable PAUSE receive, disable PAUSE transmit */ + skge->flow_status = FLOW_STAT_REM_SEND; + else if (skge->flow_control == FLOW_MODE_LOC_SEND && + (lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD) + /* Disable PAUSE receive, enable PAUSE transmit */ + skge->flow_status = FLOW_STAT_LOC_SEND; else - skge->flow_control = FLOW_MODE_NONE; - + skge->flow_status = FLOW_STAT_NONE; skge->speed = SPEED_1000; } @@ -1602,8 +1626,8 @@ static void genesis_link_up(struct skge_port *skge) * enabling pause frame reception is required for 1000BT * because the XMAC is not reset if the link is going down */ - if (skge->flow_control == FLOW_MODE_NONE || - skge->flow_control == FLOW_MODE_LOC_SEND) + if (skge->flow_status == FLOW_STAT_NONE || + skge->flow_status == FLOW_STAT_LOC_SEND) /* Disable Pause Frame Reception */ cmd |= XM_MMU_IGN_PF; else @@ -1613,8 +1637,8 @@ static void genesis_link_up(struct skge_port *skge) xm_write16(hw, port, XM_MMU_CMD, cmd); mode = xm_read32(hw, port, XM_MODE); - if (skge->flow_control == FLOW_MODE_SYMMETRIC || - skge->flow_control == FLOW_MODE_LOC_SEND) { + if (skge->flow_status== FLOW_STAT_SYMMETRIC || + skge->flow_status == FLOW_STAT_LOC_SEND) { /* * Configure Pause Frame Generation * Use internal and external Pause Frame Generation. @@ -1938,6 +1962,11 @@ static void yukon_mac_init(struct skge_hw *hw, int port) case FLOW_MODE_LOC_SEND: /* disable Rx flow-control */ reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS; + break; + case FLOW_MODE_SYMMETRIC: + case FLOW_MODE_SYM_OR_REM: + /* enable Tx & Rx flow-control */ + break; } gma_write16(hw, port, GM_GP_CTRL, reg); @@ -2132,13 +2161,11 @@ static void yukon_link_down(struct skge_port *skge) ctrl &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA); gma_write16(hw, port, GM_GP_CTRL, ctrl); - if (skge->flow_control == FLOW_MODE_REM_SEND) { + if (skge->flow_status == FLOW_STAT_REM_SEND) { + ctrl = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV); + ctrl |= PHY_M_AN_ASP; /* restore Asymmetric Pause bit */ - gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, - gm_phy_read(hw, port, - PHY_MARV_AUNE_ADV) - | PHY_M_AN_ASP); - + gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, ctrl); } yukon_reset(hw, port); @@ -2185,19 +2212,19 @@ static void yukon_phy_intr(struct skge_port *skge) /* We are using IEEE 802.3z/D5.0 Table 37-4 */ switch (phystat & PHY_M_PS_PAUSE_MSK) { case PHY_M_PS_PAUSE_MSK: - skge->flow_control = FLOW_MODE_SYMMETRIC; + skge->flow_status = FLOW_STAT_SYMMETRIC; break; case PHY_M_PS_RX_P_EN: - skge->flow_control = FLOW_MODE_REM_SEND; + skge->flow_status = FLOW_STAT_REM_SEND; break; case PHY_M_PS_TX_P_EN: - skge->flow_control = FLOW_MODE_LOC_SEND; + skge->flow_status = FLOW_STAT_LOC_SEND; break; default: - skge->flow_control = FLOW_MODE_NONE; + skge->flow_status = FLOW_STAT_NONE; } - if (skge->flow_control == FLOW_MODE_NONE || + if (skge->flow_status == FLOW_STAT_NONE || (skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF)) skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF); else @@ -3420,7 +3447,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, /* Auto speed and flow control */ skge->autoneg = AUTONEG_ENABLE; - skge->flow_control = FLOW_MODE_SYMMETRIC; + skge->flow_control = FLOW_MODE_SYM_OR_REM; skge->duplex = -1; skge->speed = -1; skge->advertising = skge_supported_modes(hw); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 9cc955c1250..537c0aaa1db 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2427,13 +2427,24 @@ struct skge_hw { struct mutex phy_mutex; }; -enum { - FLOW_MODE_NONE = 0, /* No Flow-Control */ - FLOW_MODE_LOC_SEND = 1, /* Local station sends PAUSE */ - FLOW_MODE_REM_SEND = 2, /* Symmetric or just remote */ +enum pause_control { + FLOW_MODE_NONE = 1, /* No Flow-Control */ + FLOW_MODE_LOC_SEND = 2, /* Local station sends PAUSE */ FLOW_MODE_SYMMETRIC = 3, /* Both stations may send PAUSE */ + FLOW_MODE_SYM_OR_REM = 4, /* Both stations may send PAUSE or + * just the remote station may send PAUSE + */ +}; + +enum pause_status { + FLOW_STAT_INDETERMINATED=0, /* indeterminated */ + FLOW_STAT_NONE, /* No Flow Control */ + FLOW_STAT_REM_SEND, /* Remote Station sends PAUSE */ + FLOW_STAT_LOC_SEND, /* Local station sends PAUSE */ + FLOW_STAT_SYMMETRIC, /* Both station may send PAUSE */ }; + struct skge_port { u32 msg_enable; struct skge_hw *hw; @@ -2446,9 +2457,10 @@ struct skge_port { struct net_device_stats net_stats; struct work_struct link_thread; + enum pause_control flow_control; + enum pause_status flow_status; u8 rx_csum; u8 blink_on; - u8 flow_control; u8 wol; u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */ u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */ -- cgit v1.2.3-70-g09d2 From 370de6cdc2ed27c41b313c031e4258ffa32272bc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 5 Oct 2006 15:49:53 -0700 Subject: [PATCH] skge: version 1.9 Want to be able to track downstream impact of fiber related fixes. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index d844a837a8f..e7e414928f8 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -43,7 +43,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "1.8" +#define DRV_VERSION "1.9" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 -- cgit v1.2.3-70-g09d2 From 7bd656d12119708b37414bf909ab2995473da818 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 9 Oct 2006 14:40:38 -0700 Subject: [PATCH] sky2: revert pci express extensions The pci express error handling extensions don't work unless PCI access is via mmconfig. Otherwise, all accesses to pci config registers greater than 256 fail. Since the sky2 driver has other ways of getting to PCI config space, it works around this short coming, but the pci_find_ext_capablity doesn't work. This backs out commit 91aeb3edbcf4e6ed72d138ac8c22fd68e6d717c3 Go back to hardcoding, since we know where the error registers are anyway. Fixes http://bugzilla.kernel.org/show_bug.cgi?id=7222 Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 30 ++++++++---------------------- drivers/net/sky2.h | 45 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 5a5289b7a88..1f91f30f4c6 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2220,8 +2220,7 @@ static void sky2_hw_intr(struct sky2_hw *hw) /* PCI-Express uncorrectable Error occurred */ u32 pex_err; - pex_err = sky2_pci_read32(hw, - hw->err_cap + PCI_ERR_UNCOR_STATUS); + pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT); if (net_ratelimit()) printk(KERN_ERR PFX "%s: pci express error (0x%x)\n", @@ -2229,20 +2228,15 @@ static void sky2_hw_intr(struct sky2_hw *hw) /* clear the interrupt */ sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); - sky2_pci_write32(hw, - hw->err_cap + PCI_ERR_UNCOR_STATUS, - 0xffffffffUL); + sky2_pci_write32(hw, PEX_UNC_ERR_STAT, + 0xffffffffUL); sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); - - /* In case of fatal error mask off to keep from getting stuck */ - if (pex_err & (PCI_ERR_UNC_POISON_TLP | PCI_ERR_UNC_FCP - | PCI_ERR_UNC_DLP)) { + if (pex_err & PEX_FATAL_ERRORS) { u32 hwmsk = sky2_read32(hw, B0_HWE_IMSK); hwmsk &= ~Y2_IS_PCI_EXP; sky2_write32(hw, B0_HWE_IMSK, hwmsk); } - } if (status & Y2_HWE_L1_MASK) @@ -2423,7 +2417,6 @@ static int sky2_reset(struct sky2_hw *hw) u16 status; u8 t8; int i; - u32 msk; sky2_write8(hw, B0_CTST, CS_RST_CLR); @@ -2464,13 +2457,9 @@ static int sky2_reset(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_MRST_CLR); /* clear any PEX errors */ - if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) { - hw->err_cap = pci_find_ext_capability(hw->pdev, PCI_EXT_CAP_ID_ERR); - if (hw->err_cap) - sky2_pci_write32(hw, - hw->err_cap + PCI_ERR_UNCOR_STATUS, - 0xffffffffUL); - } + if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) + sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); + hw->pmd_type = sky2_read8(hw, B2_PMD_TYP); hw->ports = 1; @@ -2527,10 +2516,7 @@ static int sky2_reset(struct sky2_hw *hw) sky2_write8(hw, RAM_BUFFER(i, B3_RI_RTO_XS2), SK_RI_TO_53); } - msk = Y2_HWE_ALL_MASK; - if (!hw->err_cap) - msk &= ~Y2_IS_PCI_EXP; - sky2_write32(hw, B0_HWE_IMSK, msk); + sky2_write32(hw, B0_HWE_IMSK, Y2_HWE_ALL_MASK); for (i = 0; i < hw->ports; i++) sky2_gmac_reset(hw, i); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index f66109a96d9..43d2accf60e 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -6,15 +6,24 @@ #define ETH_JUMBO_MTU 9000 /* Maximum MTU supported */ -/* PCI device specific config registers */ +/* PCI config registers */ enum { PCI_DEV_REG1 = 0x40, PCI_DEV_REG2 = 0x44, + PCI_DEV_STATUS = 0x7c, PCI_DEV_REG3 = 0x80, PCI_DEV_REG4 = 0x84, PCI_DEV_REG5 = 0x88, }; +enum { + PEX_DEV_CAP = 0xe4, + PEX_DEV_CTRL = 0xe8, + PEX_DEV_STA = 0xea, + PEX_LNK_STAT = 0xf2, + PEX_UNC_ERR_STAT= 0x104, +}; + /* Yukon-2 */ enum pci_dev_reg_1 { PCI_Y2_PIG_ENA = 1<<31, /* Enable Plug-in-Go (YUKON-2) */ @@ -63,6 +72,39 @@ enum pci_dev_reg_4 { PCI_STATUS_REC_MASTER_ABORT | \ PCI_STATUS_REC_TARGET_ABORT | \ PCI_STATUS_PARITY) + +enum pex_dev_ctrl { + PEX_DC_MAX_RRS_MSK = 7<<12, /* Bit 14..12: Max. Read Request Size */ + PEX_DC_EN_NO_SNOOP = 1<<11,/* Enable No Snoop */ + PEX_DC_EN_AUX_POW = 1<<10,/* Enable AUX Power */ + PEX_DC_EN_PHANTOM = 1<<9, /* Enable Phantom Functions */ + PEX_DC_EN_EXT_TAG = 1<<8, /* Enable Extended Tag Field */ + PEX_DC_MAX_PLS_MSK = 7<<5, /* Bit 7.. 5: Max. Payload Size Mask */ + PEX_DC_EN_REL_ORD = 1<<4, /* Enable Relaxed Ordering */ + PEX_DC_EN_UNS_RQ_RP = 1<<3, /* Enable Unsupported Request Reporting */ + PEX_DC_EN_FAT_ER_RP = 1<<2, /* Enable Fatal Error Reporting */ + PEX_DC_EN_NFA_ER_RP = 1<<1, /* Enable Non-Fatal Error Reporting */ + PEX_DC_EN_COR_ER_RP = 1<<0, /* Enable Correctable Error Reporting */ +}; +#define PEX_DC_MAX_RD_RQ_SIZE(x) (((x)<<12) & PEX_DC_MAX_RRS_MSK) + +/* PEX_UNC_ERR_STAT PEX Uncorrectable Errors Status Register (Yukon-2) */ +enum pex_err { + PEX_UNSUP_REQ = 1<<20, /* Unsupported Request Error */ + + PEX_MALFOR_TLP = 1<<18, /* Malformed TLP */ + + PEX_UNEXP_COMP = 1<<16, /* Unexpected Completion */ + + PEX_COMP_TO = 1<<14, /* Completion Timeout */ + PEX_FLOW_CTRL_P = 1<<13, /* Flow Control Protocol Error */ + PEX_POIS_TLP = 1<<12, /* Poisoned TLP */ + + PEX_DATA_LINK_P = 1<<4, /* Data Link Protocol Error */ + PEX_FATAL_ERRORS= (PEX_MALFOR_TLP | PEX_FLOW_CTRL_P | PEX_DATA_LINK_P), +}; + + enum csr_regs { B0_RAP = 0x0000, B0_CTST = 0x0004, @@ -1836,7 +1878,6 @@ struct sky2_hw { struct net_device *dev[2]; int pm_cap; - int err_cap; u8 chip_id; u8 chip_rev; u8 pmd_type; -- cgit v1.2.3-70-g09d2 From 6e532cfe49b6e961e1260642a44959b645e9ab54 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 9 Oct 2006 15:49:27 -0700 Subject: [PATCH] sky2: set lower pause threshold to prevent overrun Adjust the pause threshold on slower systems to keep from getting overrun. Since FIFO is 2K bytes, don't send XON pause until there is space for a full frame. Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 1f91f30f4c6..c10e7f5faa5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -683,7 +683,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON); if (hw->chip_id == CHIP_ID_YUKON_EC_U) { - sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8); + sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 512/8); sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8); if (hw->dev[port]->mtu > ETH_DATA_LEN) { /* set Tx GMAC FIFO Almost Empty Threshold */ -- cgit v1.2.3-70-g09d2 From 4a1d2d81fa327d095a0a8a1f961bace5b0a2f7da Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Fri, 6 Oct 2006 12:12:34 -0600 Subject: [PATCH] Fix section mismatch in de2104x.c WARNING: drivers/net/tulip/de2104x.o - Section mismatch: reference to .init.text:de_init_one from .data.rel.local after 'de_driver' (at offset 0x20) WARNING: drivers/net/tulip/de2104x.o - Section mismatch: reference to .exit.text:de_remove_one from .data.rel.local after 'de_driver' (at offset 0x28) Signed-off-by: Helge Deller Signed-off-by: Kyle McMartin Signed-off-by: Matthew Wilcox Signed-off-by: Jeff Garzik --- drivers/net/tulip/de2104x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 2cfd9634895..f6b3a94e97b 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1730,7 +1730,7 @@ static void __init de21040_get_media_info(struct de_private *de) } /* Note: this routine returns extra data bits for size detection. */ -static unsigned __init tulip_read_eeprom(void __iomem *regs, int location, int addr_len) +static unsigned __devinit tulip_read_eeprom(void __iomem *regs, int location, int addr_len) { int i; unsigned retval = 0; @@ -1926,7 +1926,7 @@ bad_srom: goto fill_defaults; } -static int __init de_init_one (struct pci_dev *pdev, +static int __devinit de_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *dev; @@ -2082,7 +2082,7 @@ err_out_free: return rc; } -static void __exit de_remove_one (struct pci_dev *pdev) +static void __devexit de_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct de_private *de = dev->priv; @@ -2164,7 +2164,7 @@ static struct pci_driver de_driver = { .name = DRV_NAME, .id_table = de_pci_tbl, .probe = de_init_one, - .remove = __exit_p(de_remove_one), + .remove = __devexit_p(de_remove_one), #ifdef CONFIG_PM .suspend = de_suspend, .resume = de_resume, -- cgit v1.2.3-70-g09d2