From patchwork Thu Aug 25 14:46:20 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnd Bergmann X-Patchwork-Id: 101935 Delivered-To: patch@linaro.org Received: by 10.140.29.52 with SMTP id a49csp880633qga; Thu, 25 Aug 2016 07:48:40 -0700 (PDT) X-Received: by 10.66.82.42 with SMTP id f10mr17070104pay.17.1472136515992; Thu, 25 Aug 2016 07:48:35 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id n89si15847068pfa.261.2016.08.25.07.48.35; Thu, 25 Aug 2016 07:48:35 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759057AbcHYOsd (ORCPT + 27 others); Thu, 25 Aug 2016 10:48:33 -0400 Received: from mout.kundenserver.de ([212.227.17.24]:49982 "EHLO mout.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757589AbcHYOrv (ORCPT ); Thu, 25 Aug 2016 10:47:51 -0400 Received: from wuerfel.lan. ([78.42.132.4]) by mrelayeu.kundenserver.de (mreue102) with ESMTPA (Nemesis) id 0M4Hw3-1bKiaR1UQ7-00rlbs; Thu, 25 Aug 2016 16:46:40 +0200 From: Arnd Bergmann To: Russell King Cc: linux-arm-kernel@lists.infradead.org, Arnd Bergmann , Nicolas Pitre , "David S. Miller" , Robert Jarzmik , Yoshinori Sato , netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH 1/2] smc91x: always use 8-bit access if necessary Date: Thu, 25 Aug 2016 16:46:20 +0200 Message-Id: <20160825144633.1850889-1-arnd@arndb.de> X-Mailer: git-send-email 2.9.0 X-Provags-ID: V03:K0:Ausu14cEGytXCj0o+30yjaBbeGsyb9cw8+iV8Wkj8aJWYrq+Ewy IojKtebV+nzClAY3yeqdaFR49mYd/uwxcBR22rs2/JLHV2MHBkOVpF59v+s1UGsAlHZXpah /DSHmhs66mJdmnzqEyH+a++Nov9QBwhNzHZ0vP4+JBA6sBIMafhZ5WsVoBVyxtuUyuI181o F6XK3g/H3rjOZ7XwBtIKg== X-UI-Out-Filterresults: notjunk:1; V01:K0:sH/1V7oNYyQ=:JFVzA+GRYcWOsyp9daSYi4 0l4V0ZhptrlS+DWMaZ9x0oVIgA3cFKuGwAUoTG1/wcDkizQeswLBp/mkAMyg52ahNLZk3HE98 ANqQBPwuUt4Cy9xLSvsynlvfmtBycq+DrbOIZWcl2mAzufVVPZX+KOjGyww7zdCJS3oa+E+Tt oRYevvUN3jbkkrrEmLAtTZLAF3RlR1CR1ySnS0ExEyVnM2xCmmuDDBe4+1axnbYaxjQ46LBVj cy7o+ir9DZBTEwSr6LVxuHaBxtwqi5qglnOtlGPoWTfC1ID/6e15qDINF99Q6lhb4mw66LzJv tT0IUaEDlzvG6zApHuhMNYG8QKtWOAAeYo8+97Kbvfq3YoiTOCbRytT+z4/32/YfIxZzyjG3r 1CXBDWTC5L8MtlhCYHRZ5VURJNsAkrPryBk01KYu//fJCBpqs2gFGLAmHxDu+rfqJnf/xAEnf ZnQEb6bLumTsqt4CO/Dj8pe0MgoqGnqV5rxxg9FGxy+y0KdHdEcyg5tt+2iEZA3qsWYzS5yxp mcyVKOAKp/zJRB5rF3dVeVi/u7IaZ3IGi1/q4bDbSqqEZDetLriTS/i3oWD8NlstSVS/8/A8G rLvBJ7anj2XKzVV+j62TF9C+9ZYdeC9Us53E280St5AiOq0MXnnS1+xX9pMBumkxAVcgnp0sZ SNfJcIbbJKfIksHFEIk1YxH1JZf4bkcW0Lk8tZdUoA4JNhAR2VJv8tui/FVMZox1cXaA= Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org As Russell King found out the hard way, a change I did to fix multiplatform builds with this driver broke the old Assabet/Neponset platform: It turns out that while the driver is runtime configurable in principle, the runtime configuration does not cover the specific case of machines that can not do any 16-bit I/O on the smc91x registers. The driver currently provides helpers to access 16-bit registers for architectures that are known at compile-time to only have 8-bit I/O, but my patch changed it to a runtime flag that never gets consulted most register accesses. This introduces new SMC_out16()/SMC_in16 helpers (if anyone can suggest a better name, I'm glad to modify this) that behaves like SMC_outw()/SMC_inw() most of the time, but uses a pair of 8-bit accesses on platforms that have no support for wider register accesses. Signed-off-by: Arnd Bergmann Reported-by: Russell King Fixes: b70661c70830d ("net: smc91x: use run-time configuration on all ARM machines") --- drivers/net/ethernet/smsc/smc91x.h | 125 ++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 59 deletions(-) While this patch fixes one bug on Neponset, it probably doesn't address the one that Russell ran into first, so this is for review only for now, until the remaining problem(s) have been worked out. Please ignore the first submission, I accidentally only sent out patch 2/2, which does not actually fix a bug. -- 2.9.0 diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h index 1a55c7976df0..22333477d0b5 100644 --- a/drivers/net/ethernet/smsc/smc91x.h +++ b/drivers/net/ethernet/smsc/smc91x.h @@ -414,25 +414,32 @@ smc_pxa_dma_insw(void __iomem *ioaddr, struct smc_local *lp, int reg, int dma, #define SMC_outsl(a, r, p, l) BUG() #endif -#if ! SMC_CAN_USE_16BIT - /* - * Any 16-bit access is performed with two 8-bit accesses if the hardware - * can't do it directly. Most registers are 16-bit so those are mandatory. + * Any 16-bit register access is performed with two 8-bit accesses if the + * hardware can't do it directly. */ -#define SMC_outw(x, ioaddr, reg) \ - do { \ - unsigned int __val16 = (x); \ - SMC_outb( __val16, ioaddr, reg ); \ - SMC_outb( __val16 >> 8, ioaddr, reg + (1 << SMC_IO_SHIFT));\ - } while (0) -#define SMC_inw(ioaddr, reg) \ - ({ \ - unsigned int __val16; \ - __val16 = SMC_inb( ioaddr, reg ); \ +#define SMC_out16(x, ioaddr, reg) \ +do { \ + if (SMC_CAN_USE_8BIT && !SMC_16BIT(lp)) { \ + unsigned int __val16 = (x); \ + SMC_outb(__val16, ioaddr, reg ); \ + SMC_outb(__val16 >> 8, ioaddr, reg + (1 << SMC_IO_SHIFT)); \ + } else { \ + SMC_outw(x, ioaddr, reg); \ + } \ +} while (0) + +#define SMC_in16(ioaddr, reg) \ +({ \ + unsigned int __val16; \ + if (SMC_CAN_USE_8BIT && !SMC_16BIT(lp)) { \ + __val16 = SMC_inb( ioaddr, reg ); \ __val16 |= SMC_inb( ioaddr, reg + (1 << SMC_IO_SHIFT)) << 8; \ - __val16; \ - }) + } else { \ + __val16 = SMC_inw(ioaddr, reg); \ + } \ + __val16; \ +}) #define SMC_insw(a, r, p, l) BUG() #define SMC_outsw(a, r, p, l) BUG() @@ -927,113 +934,113 @@ static const char * chip_ids[ 16 ] = { SMC_outw((x) << 8, ioaddr, INT_REG(lp)); \ } while (0) -#define SMC_CURRENT_BANK(lp) SMC_inw(ioaddr, BANK_SELECT) +#define SMC_CURRENT_BANK(lp) SMC_in16(ioaddr, BANK_SELECT) #define SMC_SELECT_BANK(lp, x) \ do { \ if (SMC_MUST_ALIGN_WRITE(lp)) \ SMC_outl((x)<<16, ioaddr, 12<> 8; \ - __v = SMC_inw(ioaddr, ADDR1_REG(lp)); \ + __v = SMC_in16(ioaddr, ADDR1_REG(lp)); \ addr[2] = __v; addr[3] = __v >> 8; \ - __v = SMC_inw(ioaddr, ADDR2_REG(lp)); \ + __v = SMC_in16(ioaddr, ADDR2_REG(lp)); \ addr[4] = __v; addr[5] = __v >> 8; \ } while (0) #endif #define SMC_SET_MAC_ADDR(lp, addr) \ do { \ - SMC_outw(addr[0]|(addr[1] << 8), ioaddr, ADDR0_REG(lp)); \ - SMC_outw(addr[2]|(addr[3] << 8), ioaddr, ADDR1_REG(lp)); \ - SMC_outw(addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG(lp)); \ + SMC_out16(addr[0]|(addr[1] << 8), ioaddr, ADDR0_REG(lp)); \ + SMC_out16(addr[2]|(addr[3] << 8), ioaddr, ADDR1_REG(lp)); \ + SMC_out16(addr[4]|(addr[5] << 8), ioaddr, ADDR2_REG(lp)); \ } while (0) #define SMC_SET_MCAST(lp, x) \ do { \ const unsigned char *mt = (x); \ - SMC_outw(mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1(lp)); \ - SMC_outw(mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2(lp)); \ - SMC_outw(mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3(lp)); \ - SMC_outw(mt[6] | (mt[7] << 8), ioaddr, MCAST_REG4(lp)); \ + SMC_out16(mt[0] | (mt[1] << 8), ioaddr, MCAST_REG1(lp)); \ + SMC_out16(mt[2] | (mt[3] << 8), ioaddr, MCAST_REG2(lp)); \ + SMC_out16(mt[4] | (mt[5] << 8), ioaddr, MCAST_REG3(lp)); \ + SMC_out16(mt[6] | (mt[7] << 8), ioaddr, MCAST_REG4(lp)); \ } while (0) #define SMC_PUT_PKT_HDR(lp, status, length) \ @@ -1042,8 +1049,8 @@ static const char * chip_ids[ 16 ] = { SMC_outl((status) | (length)<<16, ioaddr, \ DATA_REG(lp)); \ else { \ - SMC_outw(status, ioaddr, DATA_REG(lp)); \ - SMC_outw(length, ioaddr, DATA_REG(lp)); \ + SMC_out16(status, ioaddr, DATA_REG(lp)); \ + SMC_out16(length, ioaddr, DATA_REG(lp)); \ } \ } while (0) @@ -1053,9 +1060,9 @@ static const char * chip_ids[ 16 ] = { unsigned int __val = SMC_inl(ioaddr, DATA_REG(lp)); \ (status) = __val & 0xffff; \ (length) = __val >> 16; \ - } else { \ - (status) = SMC_inw(ioaddr, DATA_REG(lp)); \ - (length) = SMC_inw(ioaddr, DATA_REG(lp)); \ + } else if (SMC_16BIT(lp) { \ + (status) = SMC_in16(ioaddr, DATA_REG(lp)); \ + (length) = SMC_in16(ioaddr, DATA_REG(lp)); \ } \ } while (0)