Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756210AbYADDoT (ORCPT ); Thu, 3 Jan 2008 22:44:19 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753653AbYADDoE (ORCPT ); Thu, 3 Jan 2008 22:44:04 -0500 Received: from mail.gmx.net ([213.165.64.20]:58435 "HELO mail.gmx.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1753260AbYADDoC (ORCPT ); Thu, 3 Jan 2008 22:44:02 -0500 X-Authenticated: #5039886 X-Provags-ID: V01U2FsdGVkX19UNWVD9e9UOWNEdnb82ordtOqFiFLe/UYmPEcJl8 abPHYrNG4S7R7r Date: Fri, 4 Jan 2008 04:43:57 +0100 From: =?iso-8859-1?Q?Bj=F6rn?= Steinbrink To: Adrian Bunk Cc: Andreas Mohr , Richard Jonsson , linux-kernel@vger.kernel.org, Ayaz Abdulla , jgarzik@pobox.com, netdev@vger.kernel.org Subject: Re: forcedeth: MAC-address reversed on resume from suspend Message-ID: <20080104034357.GA2113@atjola.homenet> References: <477BFC71.7090002@coderworld.net> <20080102214843.GA19224@rhlx01.hs-esslingen.de> <20080102234209.GA10831@does.not.exist> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <20080102234209.GA10831@does.not.exist> User-Agent: Mutt/1.5.17 (2007-11-01) X-Y-GMX-Trusted: 0 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5119 Lines: 115 On 2008.01.03 01:42:09 +0200, Adrian Bunk wrote: > [ original bug report: http://lkml.org/lkml/2008/1/2/253 ] > > On Wed, Jan 02, 2008 at 10:48:43PM +0100, Andreas Mohr wrote: > > Hi, > > > > On Wed, Jan 02, 2008 at 10:04:49PM +0100, Richard Jonsson wrote: > > > Bugreport regarding forcedeth driver. > > > > > > When returning from suspend-to-RAM the MAC-address byteorder is > > > reversed. After another suspend-resume cycle the MAC-address is > > > again correct. This brings a great deal of pain since the NIC is > > > assigned a random MAC-address when it is detected as invalid. > > > > > > I cannot say if this issue appeared recently or if it's been in > > > the kernel for a while, as I've been using wireless until > > > recently. > > > > > > I read somewhere on lkml that the mac is read from the device, > > > then reversed and finally written back to the device. Can it be > > > that it is read again on resume and reversed, and then again > > > written to the device? This would explain why it's ok every other > > > resume cycle. > > > > Uh, Use The Source, Luke? > > > > But no, I think it's simply driver dainbreadness, not a matter of > > complicated writing and reading back in reversed order. > > > > drivers/net/forcedeth.c has a nice DEV_HAS_CORRECT_MACADDR flag > > which is being enabled for certain cards (those which need this) and > > disabled for others. > > > > The nv_probe() function then nicely obeys this flag by reversing the > > address if needed, _however_ there's another function, > > nv_copy_mac_to_hw(), which does _NOT_ obey it and simply copies the > > _raw_ netdev dev_addr to the card register (NvRegMacAddrA etc.). nv_copy_mac_to_hw() is called from nv_probe() _after_ the MAC address has been fixed, and from nv_set_mac_address() which is supposed to get a correct MAC address anyway. So I don't see any problem there. After some digging, I guess it's related to 5070d3408405ae1941f259acac7a9882045c3be4 That introduced a flag in a register to signal if the MAC address has been corrected, so that for example kexec won't reverse the adddress again, when calling nv_probe() again. As I know neither the suspend nor the kexec code well enough, I'll have to make a few smart guesses (let's hope that that works out *g*): a) suspend manages to reverse the MAC address again, so it must call nv_probe. And we have lost the flag that stops us from reversing the address. We cannot have lost the fixed MAC address, because then we'd always get the reversed address, and not go back and forth. I'll assume that it will also call nv_remove during suspend, because it's nicely symmetrical then :-) b) kexec does not call nv_remove, because otherwise, it would see a reversed address on its nv_probe call anyway, and the flag wouldn't be necessary. Now the commit that introduced the flag did also introduce an indirect change to nv_remove. Although it still says that it writes back the broken MAC address, that's no longer true, because orig_mac now also gets the correct address in nv_probe. Smart guessing time again: That was required because otherwise a "rmood forcedeth && modprobe forcedeth" would have produced a reversed MAC address. But that also causes the problem that we get when we loose either the flag, we start reversing the fixed address. If we instead return the card to its initial state in nv_remove, ie. unset the flag and write back the reversed address, then everyone going through nv_remove _and_ nv_probe should be happy. And kexec, which only goes through nv_probe again and doesn't loose the flag should be happy, too. Richard, could you give this a spin? And then we'd likely need someone to test that with kexec... thanks, Bj?rn --- diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index a96583c..f84c752 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -5199,10 +5199,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i dev->dev_addr[3] = (np->orig_mac[0] >> 16) & 0xff; dev->dev_addr[4] = (np->orig_mac[0] >> 8) & 0xff; dev->dev_addr[5] = (np->orig_mac[0] >> 0) & 0xff; - /* set permanent address to be correct aswell */ - np->orig_mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + - (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); - np->orig_mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); writel(txreg|NVREG_TRANSMITPOLL_MAC_ADDR_REV, base + NvRegTransmitPoll); } memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); @@ -5414,6 +5410,8 @@ static void __devexit nv_remove(struct pci_dev *pci_dev) */ writel(np->orig_mac[0], base + NvRegMacAddrA); writel(np->orig_mac[1], base + NvRegMacAddrB); + writel(readl(base + NvRegTransmitPoll) & ~NVREG_TRANSMITPOLL_MAC_ADDR_REV, + base + NvRegTransmitPoll); /* free all structures */ free_rings(dev); -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/