From e52742deef04ed7babec0f5866c867dd15d449f0 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 10 Jan 2008 14:31:30 -0800 Subject: [PATCH 01/31] hostap: section mismatch warning Fix section mismatch by changing variable name to match one of the whitelisted (allowable) names for pointing into init data: WARNING: vmlinux.o(.data+0xce618): Section mismatch: reference to .init.data:prism2_plx_id_table (between 'prism2_plx_drv_id' and 'dev_info') Signed-off-by: Randy Dunlap Acked-by: Sam Ravnborg Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_plx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index 040dc3e36410..cbf15d703201 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -608,7 +608,7 @@ static void prism2_plx_remove(struct pci_dev *pdev) MODULE_DEVICE_TABLE(pci, prism2_plx_id_table); -static struct pci_driver prism2_plx_drv_id = { +static struct pci_driver prism2_plx_driver = { .name = "hostap_plx", .id_table = prism2_plx_id_table, .probe = prism2_plx_probe, @@ -618,13 +618,13 @@ static struct pci_driver prism2_plx_drv_id = { static int __init init_prism2_plx(void) { - return pci_register_driver(&prism2_plx_drv_id); + return pci_register_driver(&prism2_plx_driver); } static void __exit exit_prism2_plx(void) { - pci_unregister_driver(&prism2_plx_drv_id); + pci_unregister_driver(&prism2_plx_driver); } From 436c8854a05add153a9003b3aa19e54851ed902f Mon Sep 17 00:00:00 2001 From: Marc Pignat Date: Fri, 11 Jan 2008 16:12:28 +0100 Subject: [PATCH 02/31] wireless/libertas support for 88w8385 sdio older revision Identifiaction of another revision of 88w8385 in sdio mode. Signed-off-by: Marc Pignat Acked-by: Pierre Ossman Signed-off-by: John W. Linville --- drivers/net/wireless/libertas/if_sdio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index b24425f74883..4f1efb108c28 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -871,6 +871,10 @@ static int if_sdio_probe(struct sdio_func *func, if (sscanf(func->card->info[i], "ID: %x", &model) == 1) break; + if (!strcmp(func->card->info[i], "IBIS Wireless SDIO Card")) { + model = 4; + break; + } } if (i == func->card->num_info) { From 8ff9d21ee2ac7eceeb6ba3da52c3472dcab435e4 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 12 Jan 2008 23:12:26 +0100 Subject: [PATCH 03/31] ipw2200: fix typo in kerneldoc Fix a typo in kerneldoc for ipw2200. Signed-off-by: Stefano Brivio Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 88062c1318a8..003f73f89efa 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -4935,7 +4935,7 @@ static int ipw_queue_reset(struct ipw_priv *priv) /** * Reclaim Tx queue entries no more used by NIC. * - * When FW adwances 'R' index, all entries between old and + * When FW advances 'R' index, all entries between old and * new 'R' index need to be reclaimed. As result, some free space * forms. If there is enough free space (> low mark), wake Tx queue. * From a38db5b6219d88e2b48f07472c436b19b864f93c Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sun, 13 Jan 2008 18:30:14 +0100 Subject: [PATCH 04/31] b43: fix use-after-free rfkill bug Fix rfkill code which caused a use-after-free bug. Signed-off-by: Stefano Brivio Acked-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/b43/rfkill.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/b43/rfkill.c b/drivers/net/wireless/b43/rfkill.c index 98cf70c5fd47..11f53cb1139e 100644 --- a/drivers/net/wireless/b43/rfkill.c +++ b/drivers/net/wireless/b43/rfkill.c @@ -138,8 +138,11 @@ void b43_rfkill_init(struct b43_wldev *dev) rfk->rfkill->user_claim_unsupported = 1; rfk->poll_dev = input_allocate_polled_device(); - if (!rfk->poll_dev) - goto err_free_rfk; + if (!rfk->poll_dev) { + rfkill_free(rfk->rfkill); + goto err_freed_rfk; + } + rfk->poll_dev->private = dev; rfk->poll_dev->poll = b43_rfkill_poll; rfk->poll_dev->poll_interval = 1000; /* msecs */ @@ -175,8 +178,7 @@ err_unreg_rfk: err_free_polldev: input_free_polled_device(rfk->poll_dev); rfk->poll_dev = NULL; -err_free_rfk: - rfkill_free(rfk->rfkill); +err_freed_rfk: rfk->rfkill = NULL; out_error: rfk->registered = 0; @@ -195,6 +197,5 @@ void b43_rfkill_exit(struct b43_wldev *dev) rfkill_unregister(rfk->rfkill); input_free_polled_device(rfk->poll_dev); rfk->poll_dev = NULL; - rfkill_free(rfk->rfkill); rfk->rfkill = NULL; } From d101f6496d51cbeb285f531dff059ce0ef28ffe3 Mon Sep 17 00:00:00 2001 From: Ivo van Doorn Date: Fri, 11 Jan 2008 20:53:07 +0100 Subject: [PATCH 05/31] rt2x00: Fix ieee80211 payload alignment As Johannes Berg indicated, the NET_IP_ALIGN doesn't need to be used for ieee80211 frames. This means we can simplify the alignment calculation to just use the result of the header size modulus 4 as frame alignment. Furthermore we shouldn't use NET_IP_ALIGN in rt2x00usb because it could be 0 on some architectures and we absolutely need to have 2 bytes reserved for possible aligning. Signed-off-by: Ivo van Doorn Signed-off-by: John W. Linville --- drivers/net/wireless/rt2x00/rt2x00pci.c | 2 +- drivers/net/wireless/rt2x00/rt2x00usb.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 6d5d9aba0b73..04663eb31950 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -149,7 +149,7 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) * The data behind the ieee80211 header must be * aligned on a 4 byte boundary. */ - align = NET_IP_ALIGN + (2 * (header_size % 4 == 0)); + align = header_size % 4; /* * Allocate the sk_buffer, initialize it and copy diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index ab4797ed94c9..568d73847dca 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -245,13 +245,20 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) * Allocate a new sk buffer to replace the current one. * If allocation fails, we should drop the current frame * so we can recycle the existing sk buffer for the new frame. + * As alignment we use 2 and not NET_IP_ALIGN because we need + * to be sure we have 2 bytes room in the head. (NET_IP_ALIGN + * can be 0 on some hardware). We use these 2 bytes for frame + * alignment later, we assume that the chance that + * header_size % 4 == 2 is bigger then header_size % 2 == 0 + * and thus optimize alignment by reserving the 2 bytes in + * advance. */ frame_size = entry->ring->data_size + entry->ring->desc_size; - skb = dev_alloc_skb(frame_size + NET_IP_ALIGN); + skb = dev_alloc_skb(frame_size + 2); if (!skb) goto skip_entry; - skb_reserve(skb, NET_IP_ALIGN); + skb_reserve(skb, 2); skb_put(skb, frame_size); /* From 227bc24d675d80de1cfb3ab72891cc932dadbc3b Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Thu, 10 Jan 2008 23:25:30 +0100 Subject: [PATCH 06/31] ipg: balance locking in irq handler Spotted-by: Signed-off-by: Francois Romieu --- drivers/net/ipg.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index dbd23bb65d1e..cd1650e99369 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -1630,6 +1630,8 @@ static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst) #ifdef JUMBO_FRAME ipg_nic_rxrestore(dev); #endif + spin_lock(&sp->lock); + /* Get interrupt source information, and acknowledge * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly, * IntRequested, MacControlFrame, LinkEvent) interrupts @@ -1647,9 +1649,7 @@ static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst) handled = 1; if (unlikely(!netif_running(dev))) - goto out; - - spin_lock(&sp->lock); + goto out_unlock; /* If RFDListEnd interrupt, restore all used RFDs. */ if (status & IPG_IS_RFD_LIST_END) { @@ -1733,9 +1733,9 @@ out_enable: ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE | IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE | IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE); - +out_unlock: spin_unlock(&sp->lock); -out: + return IRQ_RETVAL(handled); } From 0da1b995aee447656c0eb77e4e32468e37f868a3 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Thu, 10 Jan 2008 23:40:59 +0100 Subject: [PATCH 07/31] ipg: plug Tx completion leak The Tx skb release could not free more than one skb per call. Add it to the fact that the xmit handler does not check for a queue full condition and you have a recipe to leak quickly. Let's release every pending Tx descriptor which has been given back to the host CPU by the network controller. The xmit handler suggests that it is done through the IPG_TFC_TFDDONE bit. Remove the former "curr" computing: it does not produce anything usable in its current form. Signed-off-by: Francois Romieu --- drivers/net/ipg.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index cd1650e99369..9752902f2d9a 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -857,21 +857,14 @@ static void init_tfdlist(struct net_device *dev) static void ipg_nic_txfree(struct net_device *dev) { struct ipg_nic_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->ioaddr; - unsigned int curr; - u64 txd_map; - unsigned int released, pending; - - txd_map = (u64)sp->txd_map; - curr = ipg_r32(TFD_LIST_PTR_0) - - do_div(txd_map, sizeof(struct ipg_tx)) - 1; + unsigned int released, pending, dirty; IPG_DEBUG_MSG("_nic_txfree\n"); pending = sp->tx_current - sp->tx_dirty; + dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH; for (released = 0; released < pending; released++) { - unsigned int dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH; struct sk_buff *skb = sp->TxBuff[dirty]; struct ipg_tx *txfd = sp->txd + dirty; @@ -882,11 +875,8 @@ static void ipg_nic_txfree(struct net_device *dev) * If the TFDDone bit is set, free the associated * buffer. */ - if (dirty == curr) - break; - - /* Setup TFDDONE for compatible issue. */ - txfd->tfc |= cpu_to_le64(IPG_TFC_TFDDONE); + if (!(txfd->tfc & cpu_to_le64(IPG_TFC_TFDDONE))) + break; /* Free the transmit buffer. */ if (skb) { @@ -898,6 +888,7 @@ static void ipg_nic_txfree(struct net_device *dev) sp->TxBuff[dirty] = NULL; } + dirty = (dirty + 1) % IPG_TFDLIST_LENGTH; } sp->tx_dirty += released; From dafdec746f8c468bebf6b99f32a392ee6c8d0212 Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Thu, 10 Jan 2008 23:45:05 +0100 Subject: [PATCH 08/31] ipg: fix queue stop condition in the xmit handler Signed-off-by: Francois Romieu --- drivers/net/ipg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 9752902f2d9a..b234b293c11f 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -1994,7 +1994,7 @@ static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL); if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH)) - netif_wake_queue(dev); + netif_stop_queue(dev); spin_unlock_irqrestore(&sp->lock, flags); From 47cccd7d7cc1f2b6f34aadc9041fb991c6293cdd Mon Sep 17 00:00:00 2001 From: Francois Romieu Date: Thu, 10 Jan 2008 23:53:15 +0100 Subject: [PATCH 09/31] ipg: fix Tx completion irq request The current logic will only request an ack for the first pending packet. No irq is triggered as soon as the CPU submits a few packets a bit quickly. Let's request an irq for every packet instead. Signed-off-by: Francois Romieu --- drivers/net/ipg.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index b234b293c11f..50f0c17451b1 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -1934,10 +1934,7 @@ static int ipg_nic_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) */ if (sp->tenmbpsmode) txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE); - else if (!((sp->tx_current - sp->tx_dirty + 1) > - IPG_FRAMESBETWEENTXDMACOMPLETES)) { - txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE); - } + txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE); /* Based on compilation option, determine if FCS is to be * appended to transmit frame by IPG. */ From e934dd7862e7f613b2ce9730d548a0a70913c8f7 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Thu, 17 Jan 2008 16:24:57 -0800 Subject: [PATCH 10/31] bonding: fix locking in sysfs primary/active selection Fix the functions that store the primary and active slave options via sysfs to hold the correct locks in the correct order. The bond_change_active_slave and bond_select_active_slave functions both require rtnl, bond->lock for read and curr_slave_lock for write_bh, and no other locks. This is so that the lower level mode-specific functions (notably for balance-alb mode) can release locks down to just rtnl in order to call, e.g., dev_set_mac_address with the locks it expects (rtnl only). Signed-off-by: Jay Vosburgh Signed-off-by: Andy Gospodarek Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_sysfs.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 11b76b352415..28a2d803e7e5 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -1075,7 +1075,10 @@ static ssize_t bonding_store_primary(struct device *d, struct slave *slave; struct bonding *bond = to_bond(d); - write_lock_bh(&bond->lock); + rtnl_lock(); + read_lock(&bond->lock); + write_lock_bh(&bond->curr_slave_lock); + if (!USES_PRIMARY(bond->params.mode)) { printk(KERN_INFO DRV_NAME ": %s: Unable to set primary slave; %s is in mode %d\n", @@ -1109,8 +1112,8 @@ static ssize_t bonding_store_primary(struct device *d, } } out: - write_unlock_bh(&bond->lock); - + write_unlock_bh(&bond->curr_slave_lock); + read_unlock(&bond->lock); rtnl_unlock(); return count; @@ -1190,7 +1193,8 @@ static ssize_t bonding_store_active_slave(struct device *d, struct bonding *bond = to_bond(d); rtnl_lock(); - write_lock_bh(&bond->lock); + read_lock(&bond->lock); + write_lock_bh(&bond->curr_slave_lock); if (!USES_PRIMARY(bond->params.mode)) { printk(KERN_INFO DRV_NAME @@ -1247,7 +1251,8 @@ static ssize_t bonding_store_active_slave(struct device *d, } } out: - write_unlock_bh(&bond->lock); + write_unlock_bh(&bond->curr_slave_lock); + read_unlock(&bond->lock); rtnl_unlock(); return count; From e0138a66e18c6755ee29ce13b3f1142af775dc5f Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Thu, 17 Jan 2008 16:24:58 -0800 Subject: [PATCH 11/31] bonding: fix ASSERT_RTNL that produces spurious warnings Move an ASSERT_RTNL down to where we should hold only RTNL; the existing check produces spurious warnings because we hold additional locks at _bh, tripping a debug warning in spin_lock_mutex(). Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_alb.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 25b8dbf6cfd7..9b55a123c08f 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1601,9 +1601,6 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave struct slave *swap_slave; int i; - if (new_slave) - ASSERT_RTNL(); - if (bond->curr_active_slave == new_slave) { return; } @@ -1649,6 +1646,8 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); + ASSERT_RTNL(); + /* curr_active_slave must be set before calling alb_swap_mac_addr */ if (swap_slave) { /* swap mac address */ From 2543331d367c9fe54f4ba73300894bc21e0a08f4 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Thu, 17 Jan 2008 16:24:59 -0800 Subject: [PATCH 12/31] bonding: fix locking during alb failover and slave removal alb_fasten_mac_swap (actually rlb_teach_disabled_mac_on_primary) requries RTNL and no other locks. This could cause dev_set_promiscuity and/or dev_set_mac_address to be called with improper locking. Changed callers to hold only RTNL during calls to alb_fasten_mac_swap or functions calling it. Updated header comments in affected functions to reflect proper reality of locking requirements. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_alb.c | 18 ++++++++++++------ drivers/net/bonding/bond_main.c | 14 ++++++++------ 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 9b55a123c08f..b57bc9467dbe 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -979,7 +979,7 @@ static void alb_swap_mac_addr(struct bonding *bond, struct slave *slave1, struct /* * Send learning packets after MAC address swap. * - * Called with RTNL and bond->lock held for read. + * Called with RTNL and no other locks */ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1, struct slave *slave2) @@ -987,6 +987,8 @@ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1, int slaves_state_differ = (SLAVE_IS_OK(slave1) != SLAVE_IS_OK(slave2)); struct slave *disabled_slave = NULL; + ASSERT_RTNL(); + /* fasten the change in the switch */ if (SLAVE_IS_OK(slave1)) { alb_send_learning_packets(slave1, slave1->dev->dev_addr); @@ -1031,7 +1033,7 @@ static void alb_fasten_mac_swap(struct bonding *bond, struct slave *slave1, * a slave that has @slave's permanet address as its current address. * We'll make sure that that slave no longer uses @slave's permanent address. * - * Caller must hold bond lock + * Caller must hold RTNL and no other locks */ static void alb_change_hw_addr_on_detach(struct bonding *bond, struct slave *slave) { @@ -1542,7 +1544,12 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave) return 0; } -/* Caller must hold bond lock for write */ +/* + * Remove slave from tlb and rlb hash tables, and fix up MAC addresses + * if necessary. + * + * Caller must hold RTNL and no other locks + */ void bond_alb_deinit_slave(struct bonding *bond, struct slave *slave) { if (bond->slave_cnt > 1) { @@ -1658,12 +1665,11 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave bond->alb_info.rlb_enabled); } - read_lock(&bond->lock); - if (swap_slave) { alb_fasten_mac_swap(bond, swap_slave, new_slave); + read_lock(&bond->lock); } else { - /* fasten bond mac on new current slave */ + read_lock(&bond->lock); alb_send_learning_packets(new_slave, bond->dev->dev_addr); } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index b0b26036266b..77d004d3c554 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1746,7 +1746,9 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) * has been cleared (if our_slave == old_current), * but before a new active slave is selected. */ + write_unlock_bh(&bond->lock); bond_alb_deinit_slave(bond, slave); + write_lock_bh(&bond->lock); } if (oldcurrent == slave) { @@ -1905,6 +1907,12 @@ static int bond_release_all(struct net_device *bond_dev) slave_dev = slave->dev; bond_detach_slave(bond, slave); + /* now that the slave is detached, unlock and perform + * all the undo steps that should not be called from + * within a lock. + */ + write_unlock_bh(&bond->lock); + if ((bond->params.mode == BOND_MODE_TLB) || (bond->params.mode == BOND_MODE_ALB)) { /* must be called only after the slave @@ -1915,12 +1923,6 @@ static int bond_release_all(struct net_device *bond_dev) bond_compute_features(bond); - /* now that the slave is detached, unlock and perform - * all the undo steps that should not be called from - * within a lock. - */ - write_unlock_bh(&bond->lock); - bond_destroy_slave_symlinks(bond_dev, slave_dev); bond_del_vlans_from_slave(bond, slave_dev); From 3b96c858fcb27120fcba222366180c3293393ccf Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Thu, 17 Jan 2008 16:25:00 -0800 Subject: [PATCH 13/31] bonding: release slaves when master removed via sysfs Add a call to bond_release_all in the bonding netdev event handler for the master. This releases the slaves for the case of, e.g., "echo -bond0 > /sys/class/net/bonding_masters", which otherwise will spin forever waiting for references to be released. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 77d004d3c554..3ede0a2e6860 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3401,9 +3401,7 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond case NETDEV_CHANGENAME: return bond_event_changename(event_bond); case NETDEV_UNREGISTER: - /* - * TODO: remove a bond from the list? - */ + bond_release_all(event_bond->dev); break; default: break; From ece95f7fefe3afae19e641e1b3f5e64b00d5b948 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Thu, 17 Jan 2008 16:25:01 -0800 Subject: [PATCH 14/31] bonding: Fix up parameter parsing A recent change to add an additional hash policy modified bond_parse_parm, but it now does not correctly match parameters passed in via sysfs. Rewrote bond_parse_parm to handle (a) parameter matches that are substrings of one another and (b) user input with whitespace (e.g., sysfs input often has a trailing newline). Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 23 ++++++++++++++++------- drivers/net/bonding/bond_sysfs.c | 8 ++++---- drivers/net/bonding/bonding.h | 4 +++- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 3ede0a2e6860..379c5d87c804 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4540,18 +4540,27 @@ static void bond_free_all(void) /* * Convert string input module parms. Accept either the - * number of the mode or its string name. + * number of the mode or its string name. A bit complicated because + * some mode names are substrings of other names, and calls from sysfs + * may have whitespace in the name (trailing newlines, for example). */ -int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl) +int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl) { - int i; + int mode = -1, i, rv; + char modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, }; + + rv = sscanf(buf, "%d", &mode); + if (!rv) { + rv = sscanf(buf, "%20s", modestr); + if (!rv) + return -1; + } for (i = 0; tbl[i].modename; i++) { - if ((isdigit(*mode_arg) && - tbl[i].mode == simple_strtol(mode_arg, NULL, 0)) || - (strcmp(mode_arg, tbl[i].modename) == 0)) { + if (mode == tbl[i].mode) + return tbl[i].mode; + if (strcmp(modestr, tbl[i].modename) == 0) return tbl[i].mode; - } } return -1; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 28a2d803e7e5..bff4f2b84ce0 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -423,7 +423,7 @@ static ssize_t bonding_store_mode(struct device *d, goto out; } - new_value = bond_parse_parm((char *)buf, bond_mode_tbl); + new_value = bond_parse_parm(buf, bond_mode_tbl); if (new_value < 0) { printk(KERN_ERR DRV_NAME ": %s: Ignoring invalid mode value %.*s.\n", @@ -478,7 +478,7 @@ static ssize_t bonding_store_xmit_hash(struct device *d, goto out; } - new_value = bond_parse_parm((char *)buf, xmit_hashtype_tbl); + new_value = bond_parse_parm(buf, xmit_hashtype_tbl); if (new_value < 0) { printk(KERN_ERR DRV_NAME ": %s: Ignoring invalid xmit hash policy value %.*s.\n", @@ -518,7 +518,7 @@ static ssize_t bonding_store_arp_validate(struct device *d, int new_value; struct bonding *bond = to_bond(d); - new_value = bond_parse_parm((char *)buf, arp_validate_tbl); + new_value = bond_parse_parm(buf, arp_validate_tbl); if (new_value < 0) { printk(KERN_ERR DRV_NAME ": %s: Ignoring invalid arp_validate value %s\n", @@ -941,7 +941,7 @@ static ssize_t bonding_store_lacp(struct device *d, goto out; } - new_value = bond_parse_parm((char *)buf, bond_lacp_tbl); + new_value = bond_parse_parm(buf, bond_lacp_tbl); if ((new_value == 1) || (new_value == 0)) { bond->params.lacp_fast = new_value; diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index e1e4734e23ce..6d83be49899a 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -141,6 +141,8 @@ struct bond_parm_tbl { int mode; }; +#define BOND_MAX_MODENAME_LEN 20 + struct vlan_entry { struct list_head vlan_list; __be32 vlan_ip; @@ -314,7 +316,7 @@ void bond_mii_monitor(struct work_struct *); void bond_loadbalance_arp_mon(struct work_struct *); void bond_activebackup_arp_mon(struct work_struct *); void bond_set_mode_ops(struct bonding *bond, int mode); -int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl); +int bond_parse_parm(const char *mode_arg, struct bond_parm_tbl *tbl); void bond_select_active_slave(struct bonding *bond); void bond_change_active_slave(struct bonding *bond, struct slave *new_active); void bond_register_arp(struct bonding *); From 027ea0416c955778ceca7ef82e48a1dd6b4617c9 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Thu, 17 Jan 2008 16:25:02 -0800 Subject: [PATCH 15/31] bonding: fix lock ordering for rtnl and bonding_rwsem Fix the handling of rtnl and the bonding_rwsem to always be acquired in a consistent order (rtnl, then bonding_rwsem). The existing code sometimes acquired them in this order, and sometimes in the opposite order, which opens a window for deadlock between ifenslave and sysfs. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 19 ++++++++++++++ drivers/net/bonding/bond_sysfs.c | 43 ++++++++++++-------------------- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 379c5d87c804..2c6da4969382 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -4874,9 +4874,22 @@ static struct lock_class_key bonding_netdev_xmit_lock_key; int bond_create(char *name, struct bond_params *params, struct bonding **newbond) { struct net_device *bond_dev; + struct bonding *bond, *nxt; int res; rtnl_lock(); + down_write(&bonding_rwsem); + + /* Check to see if the bond already exists. */ + list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) + if (strnicmp(bond->dev->name, name, IFNAMSIZ) == 0) { + printk(KERN_ERR DRV_NAME + ": cannot add bond %s; it already exists\n", + name); + res = -EPERM; + goto out_rtnl; + } + bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "", ether_setup); if (!bond_dev) { @@ -4915,10 +4928,12 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond netif_carrier_off(bond_dev); + up_write(&bonding_rwsem); rtnl_unlock(); /* allows sysfs registration of net device */ res = bond_create_sysfs_entry(bond_dev->priv); if (res < 0) { rtnl_lock(); + down_write(&bonding_rwsem); goto out_bond; } @@ -4929,6 +4944,7 @@ out_bond: out_netdev: free_netdev(bond_dev); out_rtnl: + up_write(&bonding_rwsem); rtnl_unlock(); return res; } @@ -4949,6 +4965,9 @@ static int __init bonding_init(void) #ifdef CONFIG_PROC_FS bond_create_proc_dir(); #endif + + init_rwsem(&bonding_rwsem); + for (i = 0; i < max_bonds; i++) { res = bond_create(NULL, &bonding_defaults, NULL); if (res) diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index bff4f2b84ce0..90a1f31e8e63 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -109,11 +109,10 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t { char command[IFNAMSIZ + 1] = {0, }; char *ifname; - int res = count; + int rv, res = count; struct bonding *bond; struct bonding *nxt; - down_write(&(bonding_rwsem)); sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ ifname = command + 1; if ((strlen(command) <= 1) || @@ -121,39 +120,28 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t goto err_no_cmd; if (command[0] == '+') { - - /* Check to see if the bond already exists. */ - list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) - if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) { - printk(KERN_ERR DRV_NAME - ": cannot add bond %s; it already exists\n", - ifname); - res = -EPERM; - goto out; - } - printk(KERN_INFO DRV_NAME ": %s is being created...\n", ifname); - if (bond_create(ifname, &bonding_defaults, &bond)) { - printk(KERN_INFO DRV_NAME - ": %s interface already exists. Bond creation failed.\n", - ifname); - res = -EPERM; + rv = bond_create(ifname, &bonding_defaults, &bond); + if (rv) { + printk(KERN_INFO DRV_NAME ": Bond creation failed.\n"); + res = rv; } goto out; } if (command[0] == '-') { + rtnl_lock(); + down_write(&bonding_rwsem); + list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) if (strnicmp(bond->dev->name, ifname, IFNAMSIZ) == 0) { - rtnl_lock(); /* check the ref count on the bond's kobject. * If it's > expected, then there's a file open, * and we have to fail. */ if (atomic_read(&bond->dev->dev.kobj.kref.refcount) > expected_refcount){ - rtnl_unlock(); printk(KERN_INFO DRV_NAME ": Unable remove bond %s due to open references.\n", ifname); @@ -164,6 +152,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t ": %s is being deleted...\n", bond->dev->name); bond_destroy(bond); + up_write(&bonding_rwsem); rtnl_unlock(); goto out; } @@ -171,6 +160,8 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t printk(KERN_ERR DRV_NAME ": unable to delete non-existent bond %s\n", ifname); res = -ENODEV; + up_write(&bonding_rwsem); + rtnl_unlock(); goto out; } @@ -183,7 +174,6 @@ err_no_cmd: * get called forever, which is bad. */ out: - up_write(&(bonding_rwsem)); return res; } /* class attribute for bond_masters file. This ends up in /sys/class/net */ @@ -271,6 +261,9 @@ static ssize_t bonding_store_slaves(struct device *d, /* Note: We can't hold bond->lock here, as bond_create grabs it. */ + rtnl_lock(); + down_write(&(bonding_rwsem)); + sscanf(buffer, "%16s", command); /* IFNAMSIZ*/ ifname = command + 1; if ((strlen(command) <= 1) || @@ -336,12 +329,10 @@ static ssize_t bonding_store_slaves(struct device *d, dev->mtu = bond->dev->mtu; } } - rtnl_lock(); res = bond_enslave(bond->dev, dev); bond_for_each_slave(bond, slave, i) if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) slave->original_mtu = original_mtu; - rtnl_unlock(); if (res) { ret = res; } @@ -359,12 +350,10 @@ static ssize_t bonding_store_slaves(struct device *d, if (dev) { printk(KERN_INFO DRV_NAME ": %s: Removing slave %s\n", bond->dev->name, dev->name); - rtnl_lock(); if (bond->setup_by_slave) res = bond_release_and_destroy(bond->dev, dev); else res = bond_release(bond->dev, dev); - rtnl_unlock(); if (res) { ret = res; goto out; @@ -389,6 +378,8 @@ err_no_cmd: ret = -EPERM; out: + up_write(&(bonding_rwsem)); + rtnl_unlock(); return ret; } @@ -1423,8 +1414,6 @@ int bond_create_sysfs(void) int ret = 0; struct bonding *firstbond; - init_rwsem(&bonding_rwsem); - /* get the netdev class pointer */ firstbond = container_of(bond_dev_list.next, struct bonding, bond_list); if (!firstbond) From 5655662dab4ef044be7efd155f2f5fef2e486545 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Thu, 17 Jan 2008 16:25:03 -0800 Subject: [PATCH 16/31] bonding: Don't hold lock when calling rtnl_unlock Change bond_mii_monitor to not hold any locks when calling rtnl_unlock, as rtnl_unlock can sleep (when acquring another mutex in netdev_run_todo). Bug reported by Makito SHIOKAWA , who included a different patch. Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2c6da4969382..49a198206e3d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -2386,7 +2386,9 @@ void bond_mii_monitor(struct work_struct *work) rtnl_lock(); read_lock(&bond->lock); __bond_mii_monitor(bond, 1); - rtnl_unlock(); + read_unlock(&bond->lock); + rtnl_unlock(); /* might sleep, hold no other locks */ + read_lock(&bond->lock); } delay = ((bond->params.miimon * HZ) / 1000) ? : 1; From e236ed23f81430dc020304e2efbc0cfcdf47d9a7 Mon Sep 17 00:00:00 2001 From: Jason Uhlenkott Date: Wed, 16 Jan 2008 23:03:17 -0800 Subject: [PATCH 17/31] e1000e Kconfig: remove ref to nonexistant docs There is no Documentation/networking/e1000e.txt. Signed-off-by: Jason Uhlenkott Cc: Auke Kok Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 114771a2a133..9ae3166e3162 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1976,9 +1976,6 @@ config E1000E - More specific information on configuring the driver is in - . - To compile this driver as a module, choose M here. The module will be called e1000e. From be63a21c9573fbf88106ff0f030da5974551257b Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 15 Jan 2008 11:29:29 -0800 Subject: [PATCH 18/31] Revert "sky2: remove check for PCI wakeup setting from BIOS" This reverts commit 84cd2dfb04d23a961c5f537baa243fa54d0987ac. Some BIOS's break if Wake On Lan is enabled, and the machine can't boot. Better to have some user's have to call ethtool to enable WOL than to break a single user's boot. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 7023bbe545ee..bc15940ce1bc 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3949,7 +3949,7 @@ static __exit void sky2_debug_cleanup(void) /* Initialize network device */ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port, - int highmem) + int highmem, int wol) { struct sky2_port *sky2; struct net_device *dev = alloc_etherdev(sizeof(*sky2)); @@ -3989,7 +3989,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->speed = -1; sky2->advertising = sky2_supported_modes(hw); sky2->rx_csum = (hw->chip_id != CHIP_ID_YUKON_XL); - sky2->wol = sky2_wol_supported(hw) & WAKE_MAGIC; + sky2->wol = wol; spin_lock_init(&sky2->phy_lock); sky2->tx_pending = TX_DEF_PENDING; @@ -4086,12 +4086,24 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw) return err; } +static int __devinit pci_wake_enabled(struct pci_dev *dev) +{ + int pm = pci_find_capability(dev, PCI_CAP_ID_PM); + u16 value; + + if (!pm) + return 0; + if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value)) + return 0; + return value & PCI_PM_CTRL_PME_ENABLE; +} + static int __devinit sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *dev; struct sky2_hw *hw; - int err, using_dac = 0; + int err, using_dac = 0, wol_default; err = pci_enable_device(pdev); if (err) { @@ -4124,6 +4136,8 @@ static int __devinit sky2_probe(struct pci_dev *pdev, } } + wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0; + err = -ENOMEM; hw = kzalloc(sizeof(*hw), GFP_KERNEL); if (!hw) { @@ -4167,7 +4181,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, sky2_reset(hw); - dev = sky2_init_netdev(hw, 0, using_dac); + dev = sky2_init_netdev(hw, 0, using_dac, wol_default); if (!dev) { err = -ENOMEM; goto err_out_free_pci; @@ -4204,7 +4218,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, if (hw->ports > 1) { struct net_device *dev1; - dev1 = sky2_init_netdev(hw, 1, using_dac); + dev1 = sky2_init_netdev(hw, 1, using_dac, wol_default); if (!dev1) dev_warn(&pdev->dev, "allocation for second device failed\n"); else if ((err = register_netdev(dev1))) { From ce3ba1399d2ba81b3699a82649df0cd8223c6662 Mon Sep 17 00:00:00 2001 From: Matti Linnanvuori Date: Tue, 15 Jan 2008 06:25:27 -0800 Subject: [PATCH 19/31] Documentation: add a guideline for hard_start_xmit method Add a guideline not to modify SKBs. Signed-off-by: Matti Linnanvuori Signed-off-by: Jeff Garzik --- Documentation/networking/driver.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Documentation/networking/driver.txt b/Documentation/networking/driver.txt index 4f7da5a2bf4f..ea72d2e66ca8 100644 --- a/Documentation/networking/driver.txt +++ b/Documentation/networking/driver.txt @@ -61,7 +61,10 @@ Transmit path guidelines: 2) Do not forget to update netdev->trans_start to jiffies after each new tx packet is given to the hardware. -3) Do not forget that once you return 0 from your hard_start_xmit +3) A hard_start_xmit method must not modify the shared parts of a + cloned SKB. + +4) Do not forget that once you return 0 from your hard_start_xmit method, it is your driver's responsibility to free up the SKB and in some finite amount of time. From 2a49128f0a6edee337174ea341c1d6d7565be350 Mon Sep 17 00:00:00 2001 From: Jay Cliburn Date: Mon, 14 Jan 2008 19:56:41 -0600 Subject: [PATCH 20/31] atl1: fix frame length bug The driver sets up the hardware to accept a frame with max length equal to MTU + Ethernet header + FCS + VLAN tag, but we neglect to add the VLAN tag size to the ingress buffer. When a VLAN-tagged frame arrives, the hardware passes it, but bad things happen because the buffer is too small. This patch fixes that. Thanks to David Harris for reporting the bug and testing the fix. Tested-by: David Harris Signed-off-by: Jay Cliburn Signed-off-by: Jeff Garzik --- drivers/net/atl1/atl1_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/atl1/atl1_main.c b/drivers/net/atl1/atl1_main.c index 35b0a7dd4ef4..9200ee59d854 100644 --- a/drivers/net/atl1/atl1_main.c +++ b/drivers/net/atl1/atl1_main.c @@ -120,7 +120,7 @@ static int __devinit atl1_sw_init(struct atl1_adapter *adapter) struct atl1_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; - hw->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; + hw->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; hw->min_frame_size = ETH_ZLEN + ETH_FCS_LEN; adapter->wol = 0; @@ -688,7 +688,7 @@ static int atl1_change_mtu(struct net_device *netdev, int new_mtu) { struct atl1_adapter *adapter = netdev_priv(netdev); int old_mtu = netdev->mtu; - int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN; + int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN; if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) || (max_frame > MAX_JUMBO_FRAME_SIZE)) { @@ -853,8 +853,8 @@ static u32 atl1_configure(struct atl1_adapter *adapter) /* set Interrupt Clear Timer */ iowrite16(adapter->ict, hw->hw_addr + REG_CMBDISDMA_TIMER); - /* set MTU, 4 : VLAN */ - iowrite32(hw->max_frame_size + 4, hw->hw_addr + REG_MTU); + /* set max frame size hw will accept */ + iowrite32(hw->max_frame_size, hw->hw_addr + REG_MTU); /* jumbo size & rrd retirement timer */ value = (((u32) hw->rx_jumbo_th & RXQ_JMBOSZ_TH_MASK) From 5f490c9680561e31bf0003693f20e0c7333bbeff Mon Sep 17 00:00:00 2001 From: Sreenivasa Honnur Date: Mon, 14 Jan 2008 20:23:04 -0500 Subject: [PATCH 21/31] S2io: Fixed synchronization between scheduling of napi with card reset and close - Fixed synchronization between scheduling of napi with card reset and close by moving the enabling and disabling of napi to card up and card down functions respectively instead of open and close. Signed-off-by: Surjit Reang Signed-off-by: Ramkrishna Vepa Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index fa57c49c0c51..f2ba944e035e 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -84,7 +84,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "2.0.26.10" +#define DRV_VERSION "2.0.26.17" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -3848,8 +3848,6 @@ static int s2io_open(struct net_device *dev) netif_carrier_off(dev); sp->last_link_state = 0; - napi_enable(&sp->napi); - if (sp->config.intr_type == MSI_X) { int ret = s2io_enable_msi_x(sp); @@ -3892,7 +3890,6 @@ static int s2io_open(struct net_device *dev) return 0; hw_init_failed: - napi_disable(&sp->napi); if (sp->config.intr_type == MSI_X) { if (sp->entries) { kfree(sp->entries); @@ -3932,7 +3929,6 @@ static int s2io_close(struct net_device *dev) return 0; netif_stop_queue(dev); - napi_disable(&sp->napi); /* Reset card, kill tasklet and free Tx and Rx buffers. */ s2io_card_down(sp); @@ -6796,6 +6792,8 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) struct XENA_dev_config __iomem *bar0 = sp->bar0; unsigned long flags; register u64 val64 = 0; + struct config_param *config; + config = &sp->config; if (!is_s2io_card_up(sp)) return; @@ -6807,6 +6805,10 @@ static void do_s2io_card_down(struct s2io_nic * sp, int do_io) } clear_bit(__S2IO_STATE_CARD_UP, &sp->state); + /* Disable napi */ + if (config->napi) + napi_disable(&sp->napi); + /* disable Tx and Rx traffic on the NIC */ if (do_io) stop_nic(sp); @@ -6900,6 +6902,11 @@ static int s2io_card_up(struct s2io_nic * sp) DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i, atomic_read(&sp->rx_bufs_left[i])); } + + /* Initialise napi */ + if (config->napi) + napi_enable(&sp->napi); + /* Maintain the state prior to the open */ if (sp->promisc_flg) sp->promisc_flg = 0; From 409cd63e6ef6a1aa05baa5bbff5521d62acd246d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 13 Jan 2008 14:17:05 +0000 Subject: [PATCH 22/31] dscc4 endian fixes Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/wan/dscc4.c | 94 +++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 45 deletions(-) diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 33dc713b5301..c6f26e28e376 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -139,19 +139,21 @@ struct thingie { }; struct TxFD { - u32 state; - u32 next; - u32 data; - u32 complete; + __le32 state; + __le32 next; + __le32 data; + __le32 complete; u32 jiffies; /* Allows sizeof(TxFD) == sizeof(RxFD) + extra hack */ + /* FWIW, datasheet calls that "dummy" and says that card + * never looks at it; neither does the driver */ }; struct RxFD { - u32 state1; - u32 next; - u32 data; - u32 state2; - u32 end; + __le32 state1; + __le32 next; + __le32 data; + __le32 state2; + __le32 end; }; #define DUMMY_SKB_SIZE 64 @@ -181,7 +183,7 @@ struct RxFD { #define SCC_REG_START(dpriv) (SCC_START+(dpriv->dev_id)*SCC_OFFSET) struct dscc4_pci_priv { - u32 *iqcfg; + __le32 *iqcfg; int cfg_cur; spinlock_t lock; struct pci_dev *pdev; @@ -197,8 +199,8 @@ struct dscc4_dev_priv { struct RxFD *rx_fd; struct TxFD *tx_fd; - u32 *iqrx; - u32 *iqtx; + __le32 *iqrx; + __le32 *iqtx; /* FIXME: check all the volatile are required */ volatile u32 tx_current; @@ -298,7 +300,7 @@ struct dscc4_dev_priv { #define BrrExpMask 0x00000f00 #define BrrMultMask 0x0000003f #define EncodingMask 0x00700000 -#define Hold 0x40000000 +#define Hold cpu_to_le32(0x40000000) #define SccBusy 0x10000000 #define PowerUp 0x80000000 #define Vis 0x00001000 @@ -307,14 +309,14 @@ struct dscc4_dev_priv { #define FrameRdo 0x40 #define FrameCrc 0x20 #define FrameRab 0x10 -#define FrameAborted 0x00000200 -#define FrameEnd 0x80000000 -#define DataComplete 0x40000000 +#define FrameAborted cpu_to_le32(0x00000200) +#define FrameEnd cpu_to_le32(0x80000000) +#define DataComplete cpu_to_le32(0x40000000) #define LengthCheck 0x00008000 #define SccEvt 0x02000000 #define NoAck 0x00000200 #define Action 0x00000001 -#define HiDesc 0x20000000 +#define HiDesc cpu_to_le32(0x20000000) /* SCC events */ #define RxEvt 0xf0000000 @@ -489,8 +491,8 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv) skbuff = dpriv->tx_skbuff; for (i = 0; i < TX_RING_SIZE; i++) { if (*skbuff) { - pci_unmap_single(pdev, tx_fd->data, (*skbuff)->len, - PCI_DMA_TODEVICE); + pci_unmap_single(pdev, le32_to_cpu(tx_fd->data), + (*skbuff)->len, PCI_DMA_TODEVICE); dev_kfree_skb(*skbuff); } skbuff++; @@ -500,7 +502,7 @@ static void dscc4_release_ring(struct dscc4_dev_priv *dpriv) skbuff = dpriv->rx_skbuff; for (i = 0; i < RX_RING_SIZE; i++) { if (*skbuff) { - pci_unmap_single(pdev, rx_fd->data, + pci_unmap_single(pdev, le32_to_cpu(rx_fd->data), RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE); dev_kfree_skb(*skbuff); } @@ -522,10 +524,10 @@ static inline int try_get_rx_skb(struct dscc4_dev_priv *dpriv, dpriv->rx_skbuff[dirty] = skb; if (skb) { skb->protocol = hdlc_type_trans(skb, dev); - rx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data, - len, PCI_DMA_FROMDEVICE); + rx_fd->data = cpu_to_le32(pci_map_single(dpriv->pci_priv->pdev, + skb->data, len, PCI_DMA_FROMDEVICE)); } else { - rx_fd->data = (u32) NULL; + rx_fd->data = 0; ret = -1; } return ret; @@ -587,7 +589,7 @@ static inline int dscc4_xpr_ack(struct dscc4_dev_priv *dpriv) do { if (!(dpriv->flags & (NeedIDR | NeedIDT)) || - (dpriv->iqtx[cur] & Xpr)) + (dpriv->iqtx[cur] & cpu_to_le32(Xpr))) break; smp_rmb(); schedule_timeout_uninterruptible(10); @@ -650,8 +652,9 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, printk(KERN_DEBUG "%s: skb=0 (%s)\n", dev->name, __FUNCTION__); goto refill; } - pkt_len = TO_SIZE(rx_fd->state2); - pci_unmap_single(pdev, rx_fd->data, RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE); + pkt_len = TO_SIZE(le32_to_cpu(rx_fd->state2)); + pci_unmap_single(pdev, le32_to_cpu(rx_fd->data), + RX_MAX(HDLC_MAX_MRU), PCI_DMA_FROMDEVICE); if ((skb->data[--pkt_len] & FrameOk) == FrameOk) { stats->rx_packets++; stats->rx_bytes += pkt_len; @@ -679,7 +682,7 @@ refill: } dscc4_rx_update(dpriv, dev); rx_fd->state2 = 0x00000000; - rx_fd->end = 0xbabeface; + rx_fd->end = cpu_to_le32(0xbabeface); } static void dscc4_free1(struct pci_dev *pdev) @@ -772,8 +775,8 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev, } /* Global interrupt queue */ writel((u32)(((IRQ_RING_SIZE >> 5) - 1) << 20), ioaddr + IQLENR1); - priv->iqcfg = (u32 *) pci_alloc_consistent(pdev, - IRQ_RING_SIZE*sizeof(u32), &priv->iqcfg_dma); + priv->iqcfg = (__le32 *) pci_alloc_consistent(pdev, + IRQ_RING_SIZE*sizeof(__le32), &priv->iqcfg_dma); if (!priv->iqcfg) goto err_free_irq_5; writel(priv->iqcfg_dma, ioaddr + IQCFG); @@ -786,7 +789,7 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev, */ for (i = 0; i < dev_per_card; i++) { dpriv = priv->root + i; - dpriv->iqtx = (u32 *) pci_alloc_consistent(pdev, + dpriv->iqtx = (__le32 *) pci_alloc_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), &dpriv->iqtx_dma); if (!dpriv->iqtx) goto err_free_iqtx_6; @@ -794,7 +797,7 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev, } for (i = 0; i < dev_per_card; i++) { dpriv = priv->root + i; - dpriv->iqrx = (u32 *) pci_alloc_consistent(pdev, + dpriv->iqrx = (__le32 *) pci_alloc_consistent(pdev, IRQ_RING_SIZE*sizeof(u32), &dpriv->iqrx_dma); if (!dpriv->iqrx) goto err_free_iqrx_7; @@ -1156,8 +1159,8 @@ static int dscc4_start_xmit(struct sk_buff *skb, struct net_device *dev) dpriv->tx_skbuff[next] = skb; tx_fd = dpriv->tx_fd + next; tx_fd->state = FrameEnd | TO_STATE_TX(skb->len); - tx_fd->data = pci_map_single(ppriv->pdev, skb->data, skb->len, - PCI_DMA_TODEVICE); + tx_fd->data = cpu_to_le32(pci_map_single(ppriv->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE)); tx_fd->complete = 0x00000000; tx_fd->jiffies = jiffies; mb(); @@ -1508,7 +1511,7 @@ static irqreturn_t dscc4_irq(int irq, void *token) if (state & Cfg) { if (debug > 0) printk(KERN_DEBUG "%s: CfgIV\n", DRV_NAME); - if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & Arf) + if (priv->iqcfg[priv->cfg_cur++%IRQ_RING_SIZE] & cpu_to_le32(Arf)) printk(KERN_ERR "%s: %s failed\n", dev->name, "CFG"); if (!(state &= ~Cfg)) goto out; @@ -1541,7 +1544,7 @@ static void dscc4_tx_irq(struct dscc4_pci_priv *ppriv, try: cur = dpriv->iqtx_current%IRQ_RING_SIZE; - state = dpriv->iqtx[cur]; + state = le32_to_cpu(dpriv->iqtx[cur]); if (!state) { if (debug > 4) printk(KERN_DEBUG "%s: Tx ISR = 0x%08x\n", dev->name, @@ -1580,7 +1583,7 @@ try: tx_fd = dpriv->tx_fd + cur; skb = dpriv->tx_skbuff[cur]; if (skb) { - pci_unmap_single(ppriv->pdev, tx_fd->data, + pci_unmap_single(ppriv->pdev, le32_to_cpu(tx_fd->data), skb->len, PCI_DMA_TODEVICE); if (tx_fd->state & FrameEnd) { stats->tx_packets++; @@ -1711,7 +1714,7 @@ static void dscc4_rx_irq(struct dscc4_pci_priv *priv, try: cur = dpriv->iqrx_current%IRQ_RING_SIZE; - state = dpriv->iqrx[cur]; + state = le32_to_cpu(dpriv->iqrx[cur]); if (!state) return; dpriv->iqrx[cur] = 0; @@ -1755,7 +1758,7 @@ try: goto try; rx_fd->state1 &= ~Hold; rx_fd->state2 = 0x00000000; - rx_fd->end = 0xbabeface; + rx_fd->end = cpu_to_le32(0xbabeface); //} goto try; } @@ -1834,7 +1837,7 @@ try: hdlc_stats(dev)->rx_over_errors++; rx_fd->state1 |= Hold; rx_fd->state2 = 0x00000000; - rx_fd->end = 0xbabeface; + rx_fd->end = cpu_to_le32(0xbabeface); } else dscc4_rx_skb(dpriv, dev); } while (1); @@ -1904,8 +1907,9 @@ static struct sk_buff *dscc4_init_dummy_skb(struct dscc4_dev_priv *dpriv) skb_copy_to_linear_data(skb, version, strlen(version) % DUMMY_SKB_SIZE); tx_fd->state = FrameEnd | TO_STATE_TX(DUMMY_SKB_SIZE); - tx_fd->data = pci_map_single(dpriv->pci_priv->pdev, skb->data, - DUMMY_SKB_SIZE, PCI_DMA_TODEVICE); + tx_fd->data = cpu_to_le32(pci_map_single(dpriv->pci_priv->pdev, + skb->data, DUMMY_SKB_SIZE, + PCI_DMA_TODEVICE)); dpriv->tx_skbuff[last] = skb; } return skb; @@ -1937,8 +1941,8 @@ static int dscc4_init_ring(struct net_device *dev) tx_fd->state = FrameEnd | TO_STATE_TX(2*DUMMY_SKB_SIZE); tx_fd->complete = 0x00000000; /* FIXME: NULL should be ok - to be tried */ - tx_fd->data = dpriv->tx_fd_dma; - (tx_fd++)->next = (u32)(dpriv->tx_fd_dma + + tx_fd->data = cpu_to_le32(dpriv->tx_fd_dma); + (tx_fd++)->next = cpu_to_le32(dpriv->tx_fd_dma + (++i%TX_RING_SIZE)*sizeof(*tx_fd)); } while (i < TX_RING_SIZE); @@ -1951,12 +1955,12 @@ static int dscc4_init_ring(struct net_device *dev) /* size set by the host. Multiple of 4 bytes please */ rx_fd->state1 = HiDesc; rx_fd->state2 = 0x00000000; - rx_fd->end = 0xbabeface; + rx_fd->end = cpu_to_le32(0xbabeface); rx_fd->state1 |= TO_STATE_RX(HDLC_MAX_MRU); // FIXME: return value verifiee mais traitement suspect if (try_get_rx_skb(dpriv, dev) >= 0) dpriv->rx_dirty++; - (rx_fd++)->next = (u32)(dpriv->rx_fd_dma + + (rx_fd++)->next = cpu_to_le32(dpriv->rx_fd_dma + (++i%RX_RING_SIZE)*sizeof(*rx_fd)); } while (i < RX_RING_SIZE); From 44b1e77a0275975f3bd8bdeba6c5524105216d6d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 13 Jan 2008 14:17:15 +0000 Subject: [PATCH 23/31] wan/lmc bitfields fixes Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/wan/lmc/lmc_media.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c index 574737b55f39..c9c878cd5c72 100644 --- a/drivers/net/wan/lmc/lmc_media.c +++ b/drivers/net/wan/lmc/lmc_media.c @@ -890,16 +890,8 @@ write_av9110 (lmc_softc_t * sc, u_int32_t n, u_int32_t m, u_int32_t v, static void lmc_ssi_watchdog (lmc_softc_t * const sc) { - u_int16_t mii17; - struct ssicsr2 - { - unsigned short dtr:1, dsr:1, rts:1, cable:3, crc:1, led0:1, led1:1, - led2:1, led3:1, fifo:1, ll:1, rl:1, tm:1, loop:1; - }; - struct ssicsr2 *ssicsr; - mii17 = lmc_mii_readreg (sc, 0, 17); - ssicsr = (struct ssicsr2 *) &mii17; - if (ssicsr->cable == 7) + u_int16_t mii17 = lmc_mii_readreg (sc, 0, 17); + if (((mii17 >> 3) & 7) == 7) { lmc_led_off (sc, LMC_MII16_LED2); } From c15561f0e5615607e2b5524c4b3af64d20cd6e28 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 13 Jan 2008 14:17:25 +0000 Subject: [PATCH 24/31] sbni endian fixes Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/wan/sbni.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/wan/sbni.h b/drivers/net/wan/sbni.h index 27715e70f28b..84264510a8ed 100644 --- a/drivers/net/wan/sbni.h +++ b/drivers/net/wan/sbni.h @@ -44,9 +44,15 @@ enum { #define PR_RES 0x80 struct sbni_csr1 { - unsigned rxl : 5; - unsigned rate : 2; - unsigned : 1; +#ifdef __LITTLE_ENDIAN_BITFIELD + u8 rxl : 5; + u8 rate : 2; + u8 : 1; +#else + u8 : 1; + u8 rate : 2; + u8 rxl : 5; +#endif }; /* fields in frame header */ From b665982409fd5e4d3f1b71591d2f6badf9d2ee99 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 13 Jan 2008 14:17:35 +0000 Subject: [PATCH 25/31] 3c574, 3c515 bitfields abuse wn3_config is shared by these cards; the way we deal with it is both bad C (union abuse) and broken on big-endian. For 3c515 it's less serious (ISA cards are quite rare outside of little-endian boxen), but 3c574 is a pcmcia one and that'd better be endian-independent... Fix is the same in both cases. Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/3c515.c | 60 ++++++++++++++++++----------------- drivers/net/pcmcia/3c574_cs.c | 31 ++++++++++-------- 2 files changed, 48 insertions(+), 43 deletions(-) diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 275e7510ebaf..684bab781015 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -243,14 +243,16 @@ enum eeprom_offset { enum Window3 { /* Window 3: MAC/config bits. */ Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8, }; -union wn3_config { - int i; - struct w3_config_fields { - unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2; - int pad8:8; - unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1; - int pad24:7; - } u; +enum wn3_config { + Ram_size = 7, + Ram_width = 8, + Ram_speed = 0x30, + Rom_size = 0xc0, + Ram_split_shift = 16, + Ram_split = 3 << Ram_split_shift, + Xcvr_shift = 20, + Xcvr = 7 << Xcvr_shift, + Autoselect = 0x1000000, }; enum Window4 { @@ -614,7 +616,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, /* Read the station address from the EEPROM. */ EL3WINDOW(0); for (i = 0; i < 0x18; i++) { - short *phys_addr = (short *) dev->dev_addr; + __be16 *phys_addr = (__be16 *) dev->dev_addr; int timer; outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); /* Pause for at least 162 us. for the read to take place. */ @@ -646,22 +648,22 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, { char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" }; - union wn3_config config; + __u32 config; EL3WINDOW(3); vp->available_media = inw(ioaddr + Wn3_Options); - config.i = inl(ioaddr + Wn3_Config); + config = inl(ioaddr + Wn3_Config); if (corkscrew_debug > 1) printk(KERN_INFO " Internal config register is %4.4x, transceivers %#x.\n", - config.i, inw(ioaddr + Wn3_Options)); + config, inw(ioaddr + Wn3_Options)); printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", - 8 << config.u.ram_size, - config.u.ram_width ? "word" : "byte", - ram_split[config.u.ram_split], - config.u.autoselect ? "autoselect/" : "", - media_tbl[config.u.xcvr].name); - dev->if_port = config.u.xcvr; - vp->default_media = config.u.xcvr; - vp->autoselect = config.u.autoselect; + 8 << config & Ram_size, + config & Ram_width ? "word" : "byte", + ram_split[(config & Ram_split) >> Ram_split_shift], + config & Autoselect ? "autoselect/" : "", + media_tbl[(config & Xcvr) >> Xcvr_shift].name); + vp->default_media = (config & Xcvr) >> Xcvr_shift; + vp->autoselect = config & Autoselect ? 1 : 0; + dev->if_port = vp->default_media; } if (vp->media_override != 7) { printk(KERN_INFO " Media override to transceiver type %d (%s).\n", @@ -694,14 +696,14 @@ static int corkscrew_open(struct net_device *dev) { int ioaddr = dev->base_addr; struct corkscrew_private *vp = netdev_priv(dev); - union wn3_config config; + __u32 config; int i; /* Before initializing select the active media port. */ EL3WINDOW(3); if (vp->full_duplex) outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */ - config.i = inl(ioaddr + Wn3_Config); + config = inl(ioaddr + Wn3_Config); if (vp->media_override != 7) { if (corkscrew_debug > 1) @@ -727,12 +729,12 @@ static int corkscrew_open(struct net_device *dev) } else dev->if_port = vp->default_media; - config.u.xcvr = dev->if_port; - outl(config.i, ioaddr + Wn3_Config); + config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift); + outl(config, ioaddr + Wn3_Config); if (corkscrew_debug > 1) { printk("%s: corkscrew_open() InternalConfig %8.8x.\n", - dev->name, config.i); + dev->name, config); } outw(TxReset, ioaddr + EL3_CMD); @@ -901,7 +903,7 @@ static void corkscrew_timer(unsigned long data) ok = 1; } if (!ok) { - union wn3_config config; + __u32 config; do { dev->if_port = @@ -928,9 +930,9 @@ static void corkscrew_timer(unsigned long data) ioaddr + Wn4_Media); EL3WINDOW(3); - config.i = inl(ioaddr + Wn3_Config); - config.u.xcvr = dev->if_port; - outl(config.i, ioaddr + Wn3_Config); + config = inl(ioaddr + Wn3_Config); + config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift); + outl(config, ioaddr + Wn3_Config); outw(dev->if_port == 3 ? StartCoax : StopCoax, ioaddr + EL3_CMD); diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 288177716a49..36a7ba3134ce 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -187,14 +187,16 @@ enum Window1 { enum Window3 { /* Window 3: MAC/config bits. */ Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8, }; -union wn3_config { - int i; - struct w3_config_fields { - unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2; - int pad8:8; - unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1; - int pad24:7; - } u; +enum wn3_config { + Ram_size = 7, + Ram_width = 8, + Ram_speed = 0x30, + Rom_size = 0xc0, + Ram_split_shift = 16, + Ram_split = 3 << Ram_split_shift, + Xcvr_shift = 20, + Xcvr = 7 << Xcvr_shift, + Autoselect = 0x1000000, }; enum Window4 { /* Window 4: Xcvr/media bits. */ @@ -342,7 +344,7 @@ static int tc574_config(struct pcmcia_device *link) kio_addr_t ioaddr; __be16 *phys_addr; char *cardname; - union wn3_config config; + __u32 config; DECLARE_MAC_BUF(mac); phys_addr = (__be16 *)dev->dev_addr; @@ -401,9 +403,9 @@ static int tc574_config(struct pcmcia_device *link) outw(0<<11, ioaddr + RunnerRdCtrl); printk(KERN_INFO " ASIC rev %d,", mcr>>3); EL3WINDOW(3); - config.i = inl(ioaddr + Wn3_Config); - lp->default_media = config.u.xcvr; - lp->autoselect = config.u.autoselect; + config = inl(ioaddr + Wn3_Config); + lp->default_media = (config & Xcvr) >> Xcvr_shift; + lp->autoselect = config & Autoselect ? 1 : 0; } init_timer(&lp->media); @@ -464,8 +466,9 @@ static int tc574_config(struct pcmcia_device *link) dev->name, cardname, dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr)); printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n", - 8 << config.u.ram_size, ram_split[config.u.ram_split], - config.u.autoselect ? "autoselect " : ""); + 8 << config & Ram_size, + ram_split[(config & Ram_split) >> Ram_split_shift], + config & Autoselect ? "autoselect " : ""); return 0; From d50956af74859b4e9ba544a0211a94bc2621c1d9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 13 Jan 2008 14:17:45 +0000 Subject: [PATCH 26/31] dl2k: BMCR_t fixes broken use of bitfields; FUBAR on big-endian (and not valid C, strictly speaking). Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/dl2k.c | 78 ++++++++++++++++++++-------------------------- drivers/net/dl2k.h | 17 ---------- 2 files changed, 33 insertions(+), 62 deletions(-) diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 47cce9cad30f..badc60103d34 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -1455,7 +1455,6 @@ mii_get_media (struct net_device *dev) { ANAR_t negotiate; BMSR_t bmsr; - BMCR_t bmcr; MSCR_t mscr; MSSR_t mssr; int phy_addr; @@ -1508,15 +1507,18 @@ mii_get_media (struct net_device *dev) } /* else tx_flow, rx_flow = user select */ } else { - bmcr.image = mii_read (dev, phy_addr, MII_BMCR); - if (bmcr.bits.speed100 == 1 && bmcr.bits.speed1000 == 0) { - printk (KERN_INFO "Operating at 100 Mbps, "); - } else if (bmcr.bits.speed100 == 0 && bmcr.bits.speed1000 == 0) { - printk (KERN_INFO "Operating at 10 Mbps, "); - } else if (bmcr.bits.speed100 == 0 && bmcr.bits.speed1000 == 1) { + __u16 bmcr = mii_read (dev, phy_addr, MII_BMCR); + switch (bmcr & (MII_BMCR_SPEED_100 | MII_BMCR_SPEED_1000)) { + case MII_BMCR_SPEED_1000: printk (KERN_INFO "Operating at 1000 Mbps, "); + break; + case MII_BMCR_SPEED_100: + printk (KERN_INFO "Operating at 100 Mbps, "); + break; + case 0: + printk (KERN_INFO "Operating at 10 Mbps, "); } - if (bmcr.bits.duplex_mode) { + if (bmcr & MII_BMCR_DUPLEX_MODE) { printk ("Full duplex\n"); } else { printk ("Half duplex\n"); @@ -1538,7 +1540,7 @@ static int mii_set_media (struct net_device *dev) { PHY_SCR_t pscr; - BMCR_t bmcr; + __u16 bmcr; BMSR_t bmsr; ANAR_t anar; int phy_addr; @@ -1567,11 +1569,8 @@ mii_set_media (struct net_device *dev) /* Soft reset PHY */ mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET); - bmcr.image = 0; - bmcr.bits.an_enable = 1; - bmcr.bits.restart_an = 1; - bmcr.bits.reset = 1; - mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + bmcr = MII_BMCR_AN_ENABLE | MII_BMCR_RESTART_AN | MII_BMCR_RESET; + mii_write (dev, phy_addr, MII_BMCR, bmcr); mdelay(1); } else { /* Force speed setting */ @@ -1581,35 +1580,30 @@ mii_set_media (struct net_device *dev) mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image); /* 2) PHY Reset */ - bmcr.image = mii_read (dev, phy_addr, MII_BMCR); - bmcr.bits.reset = 1; - mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + bmcr = mii_read (dev, phy_addr, MII_BMCR); + bmcr |= MII_BMCR_RESET; + mii_write (dev, phy_addr, MII_BMCR, bmcr); /* 3) Power Down */ - bmcr.image = 0x1940; /* must be 0x1940 */ - mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + bmcr = 0x1940; /* must be 0x1940 */ + mii_write (dev, phy_addr, MII_BMCR, bmcr); mdelay (100); /* wait a certain time */ /* 4) Advertise nothing */ mii_write (dev, phy_addr, MII_ANAR, 0); /* 5) Set media and Power Up */ - bmcr.image = 0; - bmcr.bits.power_down = 1; + bmcr = MII_BMCR_POWER_DOWN; if (np->speed == 100) { - bmcr.bits.speed100 = 1; - bmcr.bits.speed1000 = 0; + bmcr |= MII_BMCR_SPEED_100; printk (KERN_INFO "Manual 100 Mbps, "); } else if (np->speed == 10) { - bmcr.bits.speed100 = 0; - bmcr.bits.speed1000 = 0; printk (KERN_INFO "Manual 10 Mbps, "); } if (np->full_duplex) { - bmcr.bits.duplex_mode = 1; + bmcr |= MII_BMCR_DUPLEX_MODE; printk ("Full duplex\n"); } else { - bmcr.bits.duplex_mode = 0; printk ("Half duplex\n"); } #if 0 @@ -1618,7 +1612,7 @@ mii_set_media (struct net_device *dev) mscr.bits.cfg_enable = 1; mscr.bits.cfg_value = 0; #endif - mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + mii_write (dev, phy_addr, MII_BMCR, bmcr); mdelay(10); } return 0; @@ -1629,7 +1623,6 @@ mii_get_media_pcs (struct net_device *dev) { ANAR_PCS_t negotiate; BMSR_t bmsr; - BMCR_t bmcr; int phy_addr; struct netdev_private *np; @@ -1661,9 +1654,9 @@ mii_get_media_pcs (struct net_device *dev) } /* else tx_flow, rx_flow = user select */ } else { - bmcr.image = mii_read (dev, phy_addr, PCS_BMCR); + __u16 bmcr = mii_read (dev, phy_addr, PCS_BMCR); printk (KERN_INFO "Operating at 1000 Mbps, "); - if (bmcr.bits.duplex_mode) { + if (bmcr & MII_BMCR_DUPLEX_MODE) { printk ("Full duplex\n"); } else { printk ("Half duplex\n"); @@ -1684,7 +1677,7 @@ mii_get_media_pcs (struct net_device *dev) static int mii_set_media_pcs (struct net_device *dev) { - BMCR_t bmcr; + __u16 bmcr; ESR_t esr; ANAR_PCS_t anar; int phy_addr; @@ -1707,29 +1700,24 @@ mii_set_media_pcs (struct net_device *dev) /* Soft reset PHY */ mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET); - bmcr.image = 0; - bmcr.bits.an_enable = 1; - bmcr.bits.restart_an = 1; - bmcr.bits.reset = 1; - mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + bmcr = MII_BMCR_AN_ENABLE | MII_BMCR_RESTART_AN | + MII_BMCR_RESET; + mii_write (dev, phy_addr, MII_BMCR, bmcr); mdelay(1); } else { /* Force speed setting */ /* PHY Reset */ - bmcr.image = 0; - bmcr.bits.reset = 1; - mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + bmcr = MII_BMCR_RESET; + mii_write (dev, phy_addr, MII_BMCR, bmcr); mdelay(10); - bmcr.image = 0; - bmcr.bits.an_enable = 0; if (np->full_duplex) { - bmcr.bits.duplex_mode = 1; + bmcr = MII_BMCR_DUPLEX_MODE; printk (KERN_INFO "Manual full duplex\n"); } else { - bmcr.bits.duplex_mode = 0; + bmcr = 0; printk (KERN_INFO "Manual half duplex\n"); } - mii_write (dev, phy_addr, MII_BMCR, bmcr.image); + mii_write (dev, phy_addr, MII_BMCR, bmcr); mdelay(10); /* Advertise nothing */ diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h index 014b77ce96df..931fd0e58f3c 100644 --- a/drivers/net/dl2k.h +++ b/drivers/net/dl2k.h @@ -298,23 +298,6 @@ enum _pcs_reg { }; /* Basic Mode Control Register */ -typedef union t_MII_BMCR { - u16 image; - struct { - u16 _bit_5_0:6; // bit 5:0 - u16 speed1000:1; // bit 6 - u16 col_test_enable:1; // bit 7 - u16 duplex_mode:1; // bit 8 - u16 restart_an:1; // bit 9 - u16 isolate:1; // bit 10 - u16 power_down:1; // bit 11 - u16 an_enable:1; // bit 12 - u16 speed100:1; // bit 13 - u16 loopback:1; // bit 14 - u16 reset:1; // bit 15 - } bits; -} BMCR_t, *PBMCR_t; - enum _mii_bmcr { MII_BMCR_RESET = 0x8000, MII_BMCR_LOOP_BACK = 0x4000, From 21b645e4c2531631992dc127cf676631a70046c8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 13 Jan 2008 14:17:55 +0000 Subject: [PATCH 27/31] dl2k: ANAR, ANLPAR fixes same story, different registers... Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/dl2k.c | 74 ++++++++++++++++++++++++++-------------------- drivers/net/dl2k.h | 66 ----------------------------------------- 2 files changed, 42 insertions(+), 98 deletions(-) diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index badc60103d34..afeea88a520a 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -1453,7 +1453,7 @@ mii_wait_link (struct net_device *dev, int wait) static int mii_get_media (struct net_device *dev) { - ANAR_t negotiate; + __u16 negotiate; BMSR_t bmsr; MSCR_t mscr; MSSR_t mssr; @@ -1469,7 +1469,7 @@ mii_get_media (struct net_device *dev) /* Auto-Negotiation not completed */ return -1; } - negotiate.image = mii_read (dev, phy_addr, MII_ANAR) & + negotiate = mii_read (dev, phy_addr, MII_ANAR) & mii_read (dev, phy_addr, MII_ANLPAR); mscr.image = mii_read (dev, phy_addr, MII_MSCR); mssr.image = mii_read (dev, phy_addr, MII_MSSR); @@ -1481,27 +1481,27 @@ mii_get_media (struct net_device *dev) np->speed = 1000; np->full_duplex = 0; printk (KERN_INFO "Auto 1000 Mbps, Half duplex\n"); - } else if (negotiate.bits.media_100BX_FD) { + } else if (negotiate & MII_ANAR_100BX_FD) { np->speed = 100; np->full_duplex = 1; printk (KERN_INFO "Auto 100 Mbps, Full duplex\n"); - } else if (negotiate.bits.media_100BX_HD) { + } else if (negotiate & MII_ANAR_100BX_HD) { np->speed = 100; np->full_duplex = 0; printk (KERN_INFO "Auto 100 Mbps, Half duplex\n"); - } else if (negotiate.bits.media_10BT_FD) { + } else if (negotiate & MII_ANAR_10BT_FD) { np->speed = 10; np->full_duplex = 1; printk (KERN_INFO "Auto 10 Mbps, Full duplex\n"); - } else if (negotiate.bits.media_10BT_HD) { + } else if (negotiate & MII_ANAR_10BT_HD) { np->speed = 10; np->full_duplex = 0; printk (KERN_INFO "Auto 10 Mbps, Half duplex\n"); } - if (negotiate.bits.pause) { + if (negotiate & MII_ANAR_PAUSE) { np->tx_flow &= 1; np->rx_flow &= 1; - } else if (negotiate.bits.asymmetric) { + } else if (negotiate & MII_ANAR_ASYMMETRIC) { np->tx_flow = 0; np->rx_flow &= 1; } @@ -1542,7 +1542,7 @@ mii_set_media (struct net_device *dev) PHY_SCR_t pscr; __u16 bmcr; BMSR_t bmsr; - ANAR_t anar; + __u16 anar; int phy_addr; struct netdev_private *np; np = netdev_priv(dev); @@ -1552,15 +1552,24 @@ mii_set_media (struct net_device *dev) if (np->an_enable) { /* Advertise capabilities */ bmsr.image = mii_read (dev, phy_addr, MII_BMSR); - anar.image = mii_read (dev, phy_addr, MII_ANAR); - anar.bits.media_100BX_FD = bmsr.bits.media_100BX_FD; - anar.bits.media_100BX_HD = bmsr.bits.media_100BX_HD; - anar.bits.media_100BT4 = bmsr.bits.media_100BT4; - anar.bits.media_10BT_FD = bmsr.bits.media_10BT_FD; - anar.bits.media_10BT_HD = bmsr.bits.media_10BT_HD; - anar.bits.pause = 1; - anar.bits.asymmetric = 1; - mii_write (dev, phy_addr, MII_ANAR, anar.image); + anar = mii_read (dev, phy_addr, MII_ANAR) & + ~MII_ANAR_100BX_FD & + ~MII_ANAR_100BX_HD & + ~MII_ANAR_100BT4 & + ~MII_ANAR_10BT_FD & + ~MII_ANAR_10BT_HD; + if (bmsr.bits.media_100BX_FD) + anar |= MII_ANAR_100BX_FD; + if (bmsr.bits.media_100BX_HD) + anar |= MII_ANAR_100BX_HD; + if (bmsr.bits.media_100BT4) + anar |= MII_ANAR_100BT4; + if (bmsr.bits.media_10BT_FD) + anar |= MII_ANAR_10BT_FD; + if (bmsr.bits.media_10BT_HD) + anar |= MII_ANAR_10BT_HD; + anar |= MII_ANAR_PAUSE | MII_ANAR_ASYMMETRIC; + mii_write (dev, phy_addr, MII_ANAR, anar); /* Enable Auto crossover */ pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR); @@ -1621,7 +1630,7 @@ mii_set_media (struct net_device *dev) static int mii_get_media_pcs (struct net_device *dev) { - ANAR_PCS_t negotiate; + __u16 negotiate; BMSR_t bmsr; int phy_addr; struct netdev_private *np; @@ -1635,20 +1644,20 @@ mii_get_media_pcs (struct net_device *dev) /* Auto-Negotiation not completed */ return -1; } - negotiate.image = mii_read (dev, phy_addr, PCS_ANAR) & + negotiate = mii_read (dev, phy_addr, PCS_ANAR) & mii_read (dev, phy_addr, PCS_ANLPAR); np->speed = 1000; - if (negotiate.bits.full_duplex) { + if (negotiate & PCS_ANAR_FULL_DUPLEX) { printk (KERN_INFO "Auto 1000 Mbps, Full duplex\n"); np->full_duplex = 1; } else { printk (KERN_INFO "Auto 1000 Mbps, half duplex\n"); np->full_duplex = 0; } - if (negotiate.bits.pause) { + if (negotiate & PCS_ANAR_PAUSE) { np->tx_flow &= 1; np->rx_flow &= 1; - } else if (negotiate.bits.asymmetric) { + } else if (negotiate & PCS_ANAR_ASYMMETRIC) { np->tx_flow = 0; np->rx_flow &= 1; } @@ -1679,7 +1688,7 @@ mii_set_media_pcs (struct net_device *dev) { __u16 bmcr; ESR_t esr; - ANAR_PCS_t anar; + __u16 anar; int phy_addr; struct netdev_private *np; np = netdev_priv(dev); @@ -1689,14 +1698,15 @@ mii_set_media_pcs (struct net_device *dev) if (np->an_enable) { /* Advertise capabilities */ esr.image = mii_read (dev, phy_addr, PCS_ESR); - anar.image = mii_read (dev, phy_addr, MII_ANAR); - anar.bits.half_duplex = - esr.bits.media_1000BT_HD | esr.bits.media_1000BX_HD; - anar.bits.full_duplex = - esr.bits.media_1000BT_FD | esr.bits.media_1000BX_FD; - anar.bits.pause = 1; - anar.bits.asymmetric = 1; - mii_write (dev, phy_addr, MII_ANAR, anar.image); + anar = mii_read (dev, phy_addr, MII_ANAR) & + ~PCS_ANAR_HALF_DUPLEX & + ~PCS_ANAR_FULL_DUPLEX; + if (esr.bits.media_1000BT_HD | esr.bits.media_1000BX_HD) + anar |= PCS_ANAR_HALF_DUPLEX; + if (esr.bits.media_1000BT_FD | esr.bits.media_1000BX_FD) + anar |= PCS_ANAR_FULL_DUPLEX; + anar |= PCS_ANAR_PAUSE | PCS_ANAR_ASYMMETRIC; + mii_write (dev, phy_addr, MII_ANAR, anar); /* Soft reset PHY */ mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET); diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h index 931fd0e58f3c..e6623085e834 100644 --- a/drivers/net/dl2k.h +++ b/drivers/net/dl2k.h @@ -357,24 +357,6 @@ enum _mii_bmsr { }; /* ANAR */ -typedef union t_MII_ANAR { - u16 image; - struct { - u16 selector:5; // bit 4:0 - u16 media_10BT_HD:1; // bit 5 - u16 media_10BT_FD:1; // bit 6 - u16 media_100BX_HD:1; // bit 7 - u16 media_100BX_FD:1; // bit 8 - u16 media_100BT4:1; // bit 9 - u16 pause:1; // bit 10 - u16 asymmetric:1; // bit 11 - u16 _bit12:1; // bit 12 - u16 remote_fault:1; // bit 13 - u16 _bit14:1; // bit 14 - u16 next_page:1; // bit 15 - } bits; -} ANAR_t, *PANAR_t; - enum _mii_anar { MII_ANAR_NEXT_PAGE = 0x8000, MII_ANAR_REMOTE_FAULT = 0x4000, @@ -390,24 +372,6 @@ enum _mii_anar { }; /* ANLPAR */ -typedef union t_MII_ANLPAR { - u16 image; - struct { - u16 selector:5; // bit 4:0 - u16 media_10BT_HD:1; // bit 5 - u16 media_10BT_FD:1; // bit 6 - u16 media_100BX_HD:1; // bit 7 - u16 media_100BX_FD:1; // bit 8 - u16 media_100BT4:1; // bit 9 - u16 pause:1; // bit 10 - u16 asymmetric:1; // bit 11 - u16 _bit12:1; // bit 12 - u16 remote_fault:1; // bit 13 - u16 _bit14:1; // bit 14 - u16 next_page:1; // bit 15 - } bits; -} ANLPAR_t, *PANLPAR_t; - enum _mii_anlpar { MII_ANLPAR_NEXT_PAGE = MII_ANAR_NEXT_PAGE, MII_ANLPAR_REMOTE_FAULT = MII_ANAR_REMOTE_FAULT, @@ -539,21 +503,6 @@ typedef enum t_MII_ADMIN_STATUS { /* PCS control and status registers bitmap as the same as MII */ /* PCS Extended Status register bitmap as the same as MII */ /* PCS ANAR */ -typedef union t_PCS_ANAR { - u16 image; - struct { - u16 _bit_4_0:5; // bit 4:0 - u16 full_duplex:1; // bit 5 - u16 half_duplex:1; // bit 6 - u16 asymmetric:1; // bit 7 - u16 pause:1; // bit 8 - u16 _bit_11_9:3; // bit 11:9 - u16 remote_fault:2; // bit 13:12 - u16 _bit_14:1; // bit 14 - u16 next_page:1; // bit 15 - } bits; -} ANAR_PCS_t, *PANAR_PCS_t; - enum _pcs_anar { PCS_ANAR_NEXT_PAGE = 0x8000, PCS_ANAR_REMOTE_FAULT = 0x3000, @@ -563,21 +512,6 @@ enum _pcs_anar { PCS_ANAR_FULL_DUPLEX = 0x0020, }; /* PCS ANLPAR */ -typedef union t_PCS_ANLPAR { - u16 image; - struct { - u16 _bit_4_0:5; // bit 4:0 - u16 full_duplex:1; // bit 5 - u16 half_duplex:1; // bit 6 - u16 asymmetric:1; // bit 7 - u16 pause:1; // bit 8 - u16 _bit_11_9:3; // bit 11:9 - u16 remote_fault:2; // bit 13:12 - u16 _bit_14:1; // bit 14 - u16 next_page:1; // bit 15 - } bits; -} ANLPAR_PCS_t, *PANLPAR_PCS_t; - enum _pcs_anlpar { PCS_ANLPAR_NEXT_PAGE = PCS_ANAR_NEXT_PAGE, PCS_ANLPAR_REMOTE_FAULT = PCS_ANAR_REMOTE_FAULT, From 96d768517eef3c10d4a82bd121caa42f584082cb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 13 Jan 2008 14:18:05 +0000 Subject: [PATCH 28/31] dl2k: BMSR fixes Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/dl2k.c | 32 ++++++++++++++++---------------- drivers/net/dl2k.h | 22 ---------------------- 2 files changed, 16 insertions(+), 38 deletions(-) diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index afeea88a520a..4468e0f5d16e 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -1435,7 +1435,7 @@ mii_write (struct net_device *dev, int phy_addr, int reg_num, u16 data) static int mii_wait_link (struct net_device *dev, int wait) { - BMSR_t bmsr; + __u16 bmsr; int phy_addr; struct netdev_private *np; @@ -1443,8 +1443,8 @@ mii_wait_link (struct net_device *dev, int wait) phy_addr = np->phy_addr; do { - bmsr.image = mii_read (dev, phy_addr, MII_BMSR); - if (bmsr.bits.link_status) + bmsr = mii_read (dev, phy_addr, MII_BMSR); + if (bmsr & MII_BMSR_LINK_STATUS) return 0; mdelay (1); } while (--wait > 0); @@ -1454,7 +1454,7 @@ static int mii_get_media (struct net_device *dev) { __u16 negotiate; - BMSR_t bmsr; + __u16 bmsr; MSCR_t mscr; MSSR_t mssr; int phy_addr; @@ -1463,9 +1463,9 @@ mii_get_media (struct net_device *dev) np = netdev_priv(dev); phy_addr = np->phy_addr; - bmsr.image = mii_read (dev, phy_addr, MII_BMSR); + bmsr = mii_read (dev, phy_addr, MII_BMSR); if (np->an_enable) { - if (!bmsr.bits.an_complete) { + if (!(bmsr & MII_BMSR_AN_COMPLETE)) { /* Auto-Negotiation not completed */ return -1; } @@ -1541,7 +1541,7 @@ mii_set_media (struct net_device *dev) { PHY_SCR_t pscr; __u16 bmcr; - BMSR_t bmsr; + __u16 bmsr; __u16 anar; int phy_addr; struct netdev_private *np; @@ -1551,22 +1551,22 @@ mii_set_media (struct net_device *dev) /* Does user set speed? */ if (np->an_enable) { /* Advertise capabilities */ - bmsr.image = mii_read (dev, phy_addr, MII_BMSR); + bmsr = mii_read (dev, phy_addr, MII_BMSR); anar = mii_read (dev, phy_addr, MII_ANAR) & ~MII_ANAR_100BX_FD & ~MII_ANAR_100BX_HD & ~MII_ANAR_100BT4 & ~MII_ANAR_10BT_FD & ~MII_ANAR_10BT_HD; - if (bmsr.bits.media_100BX_FD) + if (bmsr & MII_BMSR_100BX_FD) anar |= MII_ANAR_100BX_FD; - if (bmsr.bits.media_100BX_HD) + if (bmsr & MII_BMSR_100BX_HD) anar |= MII_ANAR_100BX_HD; - if (bmsr.bits.media_100BT4) + if (bmsr & MII_BMSR_100BT4) anar |= MII_ANAR_100BT4; - if (bmsr.bits.media_10BT_FD) + if (bmsr & MII_BMSR_10BT_FD) anar |= MII_ANAR_10BT_FD; - if (bmsr.bits.media_10BT_HD) + if (bmsr & MII_BMSR_10BT_HD) anar |= MII_ANAR_10BT_HD; anar |= MII_ANAR_PAUSE | MII_ANAR_ASYMMETRIC; mii_write (dev, phy_addr, MII_ANAR, anar); @@ -1631,16 +1631,16 @@ static int mii_get_media_pcs (struct net_device *dev) { __u16 negotiate; - BMSR_t bmsr; + __u16 bmsr; int phy_addr; struct netdev_private *np; np = netdev_priv(dev); phy_addr = np->phy_addr; - bmsr.image = mii_read (dev, phy_addr, PCS_BMSR); + bmsr = mii_read (dev, phy_addr, PCS_BMSR); if (np->an_enable) { - if (!bmsr.bits.an_complete) { + if (!(bmsr & MII_BMSR_AN_COMPLETE)) { /* Auto-Negotiation not completed */ return -1; } diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h index e6623085e834..c8aacf2ff8da 100644 --- a/drivers/net/dl2k.h +++ b/drivers/net/dl2k.h @@ -316,28 +316,6 @@ enum _mii_bmcr { }; /* Basic Mode Status Register */ -typedef union t_MII_BMSR { - u16 image; - struct { - u16 ext_capability:1; // bit 0 - u16 japper_detect:1; // bit 1 - u16 link_status:1; // bit 2 - u16 an_ability:1; // bit 3 - u16 remote_fault:1; // bit 4 - u16 an_complete:1; // bit 5 - u16 preamble_supp:1; // bit 6 - u16 _bit_7:1; // bit 7 - u16 ext_status:1; // bit 8 - u16 media_100BT2_HD:1; // bit 9 - u16 media_100BT2_FD:1; // bit 10 - u16 media_10BT_HD:1; // bit 11 - u16 media_10BT_FD:1; // bit 12 - u16 media_100BX_HD:1; // bit 13 - u16 media_100BX_FD:1; // bit 14 - u16 media_100BT4:1; // bit 15 - } bits; -} BMSR_t, *PBMSR_t; - enum _mii_bmsr { MII_BMSR_100BT4 = 0x8000, MII_BMSR_100BX_FD = 0x4000, From 5b5119167b724f4c4d54e69f91f22a83b01207af Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 13 Jan 2008 14:18:15 +0000 Subject: [PATCH 29/31] dl2k: MSCR, MSSR, ESR, PHY_SCR fixes Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/dl2k.c | 40 ++++++++++++++++++++-------------------- drivers/net/dl2k.h | 40 ++-------------------------------------- 2 files changed, 22 insertions(+), 58 deletions(-) diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 4468e0f5d16e..2e13eaad1708 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -1455,8 +1455,8 @@ mii_get_media (struct net_device *dev) { __u16 negotiate; __u16 bmsr; - MSCR_t mscr; - MSSR_t mssr; + __u16 mscr; + __u16 mssr; int phy_addr; struct netdev_private *np; @@ -1471,13 +1471,13 @@ mii_get_media (struct net_device *dev) } negotiate = mii_read (dev, phy_addr, MII_ANAR) & mii_read (dev, phy_addr, MII_ANLPAR); - mscr.image = mii_read (dev, phy_addr, MII_MSCR); - mssr.image = mii_read (dev, phy_addr, MII_MSSR); - if (mscr.bits.media_1000BT_FD & mssr.bits.lp_1000BT_FD) { + mscr = mii_read (dev, phy_addr, MII_MSCR); + mssr = mii_read (dev, phy_addr, MII_MSSR); + if (mscr & MII_MSCR_1000BT_FD && mssr & MII_MSSR_LP_1000BT_FD) { np->speed = 1000; np->full_duplex = 1; printk (KERN_INFO "Auto 1000 Mbps, Full duplex\n"); - } else if (mscr.bits.media_1000BT_HD & mssr.bits.lp_1000BT_HD) { + } else if (mscr & MII_MSCR_1000BT_HD && mssr & MII_MSSR_LP_1000BT_HD) { np->speed = 1000; np->full_duplex = 0; printk (KERN_INFO "Auto 1000 Mbps, Half duplex\n"); @@ -1539,7 +1539,7 @@ mii_get_media (struct net_device *dev) static int mii_set_media (struct net_device *dev) { - PHY_SCR_t pscr; + __u16 pscr; __u16 bmcr; __u16 bmsr; __u16 anar; @@ -1572,9 +1572,9 @@ mii_set_media (struct net_device *dev) mii_write (dev, phy_addr, MII_ANAR, anar); /* Enable Auto crossover */ - pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR); - pscr.bits.mdi_crossover_mode = 3; /* 11'b */ - mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image); + pscr = mii_read (dev, phy_addr, MII_PHY_SCR); + pscr |= 3 << 5; /* 11'b */ + mii_write (dev, phy_addr, MII_PHY_SCR, pscr); /* Soft reset PHY */ mii_write (dev, phy_addr, MII_BMCR, MII_BMCR_RESET); @@ -1584,9 +1584,9 @@ mii_set_media (struct net_device *dev) } else { /* Force speed setting */ /* 1) Disable Auto crossover */ - pscr.image = mii_read (dev, phy_addr, MII_PHY_SCR); - pscr.bits.mdi_crossover_mode = 0; - mii_write (dev, phy_addr, MII_PHY_SCR, pscr.image); + pscr = mii_read (dev, phy_addr, MII_PHY_SCR); + pscr &= ~(3 << 5); + mii_write (dev, phy_addr, MII_PHY_SCR, pscr); /* 2) PHY Reset */ bmcr = mii_read (dev, phy_addr, MII_BMCR); @@ -1617,9 +1617,9 @@ mii_set_media (struct net_device *dev) } #if 0 /* Set 1000BaseT Master/Slave setting */ - mscr.image = mii_read (dev, phy_addr, MII_MSCR); - mscr.bits.cfg_enable = 1; - mscr.bits.cfg_value = 0; + mscr = mii_read (dev, phy_addr, MII_MSCR); + mscr |= MII_MSCR_CFG_ENABLE; + mscr &= ~MII_MSCR_CFG_VALUE = 0; #endif mii_write (dev, phy_addr, MII_BMCR, bmcr); mdelay(10); @@ -1687,7 +1687,7 @@ static int mii_set_media_pcs (struct net_device *dev) { __u16 bmcr; - ESR_t esr; + __u16 esr; __u16 anar; int phy_addr; struct netdev_private *np; @@ -1697,13 +1697,13 @@ mii_set_media_pcs (struct net_device *dev) /* Auto-Negotiation? */ if (np->an_enable) { /* Advertise capabilities */ - esr.image = mii_read (dev, phy_addr, PCS_ESR); + esr = mii_read (dev, phy_addr, PCS_ESR); anar = mii_read (dev, phy_addr, MII_ANAR) & ~PCS_ANAR_HALF_DUPLEX & ~PCS_ANAR_FULL_DUPLEX; - if (esr.bits.media_1000BT_HD | esr.bits.media_1000BX_HD) + if (esr & (MII_ESR_1000BT_HD | MII_ESR_1000BX_HD)) anar |= PCS_ANAR_HALF_DUPLEX; - if (esr.bits.media_1000BT_FD | esr.bits.media_1000BX_FD) + if (esr & (MII_ESR_1000BT_FD | MII_ESR_1000BX_FD)) anar |= PCS_ANAR_FULL_DUPLEX; anar |= PCS_ANAR_PAUSE | PCS_ANAR_ASYMMETRIC; mii_write (dev, phy_addr, MII_ANAR, anar); diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h index c8aacf2ff8da..5f00ecb4a280 100644 --- a/drivers/net/dl2k.h +++ b/drivers/net/dl2k.h @@ -385,19 +385,6 @@ enum _mii_aner { }; /* MASTER-SLAVE Control Register */ -typedef union t_MII_MSCR { - u16 image; - struct { - u16 _bit_7_0:8; // bit 7:0 - u16 media_1000BT_HD:1; // bit 8 - u16 media_1000BT_FD:1; // bit 9 - u16 port_type:1; // bit 10 - u16 cfg_value:1; // bit 11 - u16 cfg_enable:1; // bit 12 - u16 test_mode:3; // bit 15:13 - } bits; -} MSCR_t, *PMSCR_t; - enum _mii_mscr { MII_MSCR_TEST_MODE = 0xe000, MII_MSCR_CFG_ENABLE = 0x1000, @@ -408,20 +395,6 @@ enum _mii_mscr { }; /* MASTER-SLAVE Status Register */ -typedef union t_MII_MSSR { - u16 image; - struct { - u16 idle_err_count:8; // bit 7:0 - u16 _bit_9_8:2; // bit 9:8 - u16 lp_1000BT_HD:1; // bit 10 - u16 lp_1000BT_FD:1; // bit 11 - u16 remote_rcv_status:1; // bit 12 - u16 local_rcv_status:1; // bit 13 - u16 cfg_resolution:1; // bit 14 - u16 cfg_fault:1; // bit 15 - } bits; -} MSSR_t, *PMSSR_t; - enum _mii_mssr { MII_MSSR_CFG_FAULT = 0x8000, MII_MSSR_CFG_RES = 0x4000, @@ -433,17 +406,6 @@ enum _mii_mssr { }; /* IEEE Extened Status Register */ -typedef union t_MII_ESR { - u16 image; - struct { - u16 _bit_11_0:12; // bit 11:0 - u16 media_1000BT_HD:2; // bit 12 - u16 media_1000BT_FD:1; // bit 13 - u16 media_1000BX_HD:1; // bit 14 - u16 media_1000BX_FD:1; // bit 15 - } bits; -} ESR_t, *PESR_t; - enum _mii_esr { MII_ESR_1000BX_FD = 0x8000, MII_ESR_1000BX_HD = 0x4000, @@ -451,6 +413,7 @@ enum _mii_esr { MII_ESR_1000BT_HD = 0x1000, }; /* PHY Specific Control Register */ +#if 0 typedef union t_MII_PHY_SCR { u16 image; struct { @@ -468,6 +431,7 @@ typedef union t_MII_PHY_SCR { u16 xmit_fifo_depth:2; // bit 15:14 } bits; } PHY_SCR_t, *PPHY_SCR_t; +#endif typedef enum t_MII_ADMIN_STATUS { adm_reset, From 0ca5f319f4bef00d31a21614345ecd5ea0ca8afd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 13 Jan 2008 14:18:25 +0000 Subject: [PATCH 30/31] dl2k: the rest remove an unused union-with-bitfield of the same sort, add missing conversions in debugging printk Signed-off-by: Al Viro Signed-off-by: Jeff Garzik --- drivers/net/dl2k.c | 7 ++++--- drivers/net/dl2k.h | 12 ------------ 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 2e13eaad1708..e233d04a2132 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -1316,9 +1316,10 @@ rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) ("%02x:cur:%08x next:%08x status:%08x frag1:%08x frag0:%08x", i, (u32) (np->tx_ring_dma + i * sizeof (*desc)), - (u32) desc->next_desc, - (u32) desc->status, (u32) (desc->fraginfo >> 32), - (u32) desc->fraginfo); + (u32)le64_to_cpu(desc->next_desc), + (u32)le64_to_cpu(desc->status), + (u32)(le64_to_cpu(desc->fraginfo) >> 32), + (u32)le64_to_cpu(desc->fraginfo)); printk ("\n"); } printk ("\n"); diff --git a/drivers/net/dl2k.h b/drivers/net/dl2k.h index 5f00ecb4a280..d66c605b4075 100644 --- a/drivers/net/dl2k.h +++ b/drivers/net/dl2k.h @@ -364,18 +364,6 @@ enum _mii_anlpar { }; /* Auto-Negotiation Expansion Register */ -typedef union t_MII_ANER { - u16 image; - struct { - u16 lp_negotiable:1; // bit 0 - u16 page_received:1; // bit 1 - u16 nextpagable:1; // bit 2 - u16 lp_nextpagable:1; // bit 3 - u16 pdetect_fault:1; // bit 4 - u16 _bit15_5:11; // bit 15:5 - } bits; -} ANER_t, *PANER_t; - enum _mii_aner { MII_ANER_PAR_DETECT_FAULT = 0x0010, MII_ANER_LP_NEXTPAGABLE = 0x0008, From ba596a01886b236c8171fc28d53842da0128224e Mon Sep 17 00:00:00 2001 From: Matteo Croce Date: Sat, 12 Jan 2008 19:05:23 +0100 Subject: [PATCH 31/31] Replace cpmac fix Please apply this patch since i reverted by mistake the commit 4e3ab47a547616e583c7a5458beced6aa34c8ef3 in 6cd043d99dcf5d252fcc682958541f449113f7b3 Signed-off-by: Matteo Croce Signed-off-by: Jeff Garzik --- drivers/net/cpmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 6fd95a2c8cec..6e12d48351b8 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -459,7 +459,7 @@ static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; len = max(skb->len, ETH_ZLEN); - queue = skb->queue_mapping; + queue = skb_get_queue_mapping(skb); #ifdef CONFIG_NETDEVICES_MULTIQUEUE netif_stop_subqueue(dev, queue); #else