From owner-freebsd-arm@FreeBSD.ORG Mon Apr 18 11:06:55 2011 Return-Path: Delivered-To: freebsd-arm@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A2060106567C for ; Mon, 18 Apr 2011 11:06:55 +0000 (UTC) (envelope-from owner-bugmaster@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 8F6F68FC26 for ; Mon, 18 Apr 2011 11:06:55 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id p3IB6tmA019432 for ; Mon, 18 Apr 2011 11:06:55 GMT (envelope-from owner-bugmaster@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p3IB6sDh019430 for freebsd-arm@FreeBSD.org; Mon, 18 Apr 2011 11:06:54 GMT (envelope-from owner-bugmaster@FreeBSD.org) Date: Mon, 18 Apr 2011 11:06:54 GMT Message-Id: <201104181106.p3IB6sDh019430@freefall.freebsd.org> X-Authentication-Warning: freefall.freebsd.org: gnats set sender to owner-bugmaster@FreeBSD.org using -f From: FreeBSD bugmaster To: freebsd-arm@FreeBSD.org Cc: Subject: Current problem reports assigned to freebsd-arm@FreeBSD.org X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Porting FreeBSD to the StrongARM Processor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Apr 2011 11:06:55 -0000 Note: to view an individual PR, use: http://www.freebsd.org/cgi/query-pr.cgi?pr=(number). The following is a listing of current problems submitted by FreeBSD users. These represent problem reports covering all versions including experimental development code and obsolete releases. S Tracker Resp. Description -------------------------------------------------------------------------------- o arm/155894 arm [patch] Enable at91 booting from SDHC (high capacity) o arm/155214 arm [patch] MMC/SD IO slow on Atmel ARM with modern large o arm/154306 arm named crashes with signal 11 o arm/154227 arm [geli] using GELI leads to panic on ARM o arm/154189 arm lang/perl5.12 doesn't build on arm o arm/153380 arm Panic / translation fault with wlan on ARM o arm/150581 arm [irq] Unknown error generates IRQ address decoding err o arm/149288 arm mail/dovecot causes panic during configure on Sheevapl o arm/134368 arm [patch] nslu2_led driver for the LEDs on the NSLU2 p arm/134338 arm [patch] Lock GPIO accesses on ixp425 10 problems total. From owner-freebsd-arm@FreeBSD.ORG Mon Apr 18 11:33:33 2011 Return-Path: Delivered-To: freebsd-arm@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id DC84B106566B for ; Mon, 18 Apr 2011 11:33:33 +0000 (UTC) (envelope-from abuse@cj-vollblutaraber.de) Received: from res7.worldserver.net (res7.worldserver.net [217.13.199.17]) by mx1.freebsd.org (Postfix) with SMTP id 2A3848FC1F for ; Mon, 18 Apr 2011 11:33:32 +0000 (UTC) Received: (qmail 3880 invoked by uid 65534); 18 Apr 2011 11:22:09 -0000 Date: 18 Apr 2011 11:22:09 -0000 Message-ID: <20110418112209.3879.qmail@res7.worldserver.net> To: freebsd-arm@freebsd.org From: Dr.Ban Ki-moon. MIME-Version: 1.0 Content-Type: text/plain Content-Transfer-Encoding: 8bit Subject: Congratulation, URGENT RESPONSE IS NEEDED X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: courierservice@one.co.il List-Id: Porting FreeBSD to the StrongARM Processor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Apr 2011 11:33:33 -0000 Congratulation, I just received a call from the Director of Scarlet Courier Service Company Nigeria that the consignment box that was sent to you was returned due to wrong address, This consignment box contained your $5.500.000.00 united state dollars, Your compensation fund.Therefore call the director (Williams Wright) on Tel: (+234705-550-1921 ) email him at: (couierservice@one.co.il) and give him your correct address and Phone number: So the Information you are Required to Reconfirm to the Agent is as Follow. (1)Your Full Name============= (2)Mobile Phone Number====== (3)Current Home Address======== (4)Occupation================= (5)Fax Number================ (6)Country==================== (7)City===================== (8)Nearest Airport ============== (9)A Copy of Your I D For Identification Use this code (XA-8550) as the subject of your mail to them for identification. Yours Truly. Dr. Ban Ki-moon. From owner-freebsd-arm@FreeBSD.ORG Mon Apr 18 11:59:30 2011 Return-Path: Delivered-To: freebsd-arm@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id ADA26106566C for ; Mon, 18 Apr 2011 11:59:30 +0000 (UTC) (envelope-from nigel@nobiscuit.com) Received: from snippy.nobiscuit.com (snippy.nobiscuit.com [50.17.199.227]) by mx1.freebsd.org (Postfix) with ESMTP id 841408FC08 for ; Mon, 18 Apr 2011 11:59:30 +0000 (UTC) Received: by snippy.nobiscuit.com (Postfix, from userid 1001) id C6916D2005; Mon, 18 Apr 2011 11:40:15 +0000 (UTC) Date: Mon, 18 Apr 2011 11:40:15 +0000 From: Nigel Roberts To: freebsd-arm@freebsd.org Message-ID: <20110418114015.GA4277@snippy.nobiscuit.com> References: <20110322154505.GH1351@nereid> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20110322154505.GH1351@nereid> User-Agent: Mutt/1.5.20 (2009-06-14) Subject: Re: Iomega iConnect and FreeBSD (kirkwood) X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Porting FreeBSD to the StrongARM Processor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Apr 2011 11:59:30 -0000 On Tue, 22 Mar 2011 at 16:45:05 +0100, Kristof Provost wrote: > I'm not familiar with that platform, but I remember seeing a very > similar error when I was playing with an Orion based board. > The driver should be the same (mge). > The panic occurs because the cleanup code is incorrect. This problem is > fixed in current I think. > > In this case you probably don't need to worry about the cleanup code > though. It's only triggered when the PHY is not found. > If you can fix the PHY detection you won't run into the panic any more. > In 8.2 mge assumes a static mapping between interface number and PHY > address (i.e. PHY address = interface number (0 here) + 8). > You can overrule the offset by defining MII_ADDRESS_BASE. > Of course, you'll need to know the correct offset first. I'm also trying to get FreeBSD working on an Iomega device (an IX2-200) and the issue is not that the address for the PHY is wrong, it's that the first mge MAC doesn't actually have a PHY attached. Only the second MAC has a PHY (I've checked on the PCB and have pics for the curious). In Linux, only eth1 is usable, although eth0 is detected. I'd really like to get this working in FreeBSD-STABLE. Can someone please point me to where the cleanup code has been fixed in CURRENT so that I can have a go at figuring out a patch? I also had a go at getting FreeBSD-CURRENT working, but it wouldn't even get to the copyright message on boot. I'm wondering if I got the fdt config wrong, so I am going to check on that. Thanks, Nigel From owner-freebsd-arm@FreeBSD.ORG Mon Apr 18 13:25:19 2011 Return-Path: Delivered-To: freebsd-arm@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 1B31B1065680 for ; Mon, 18 Apr 2011 13:25:19 +0000 (UTC) (envelope-from kristof@sigsegv.be) Received: from brigitte.telenet-ops.be (brigitte.telenet-ops.be [195.130.137.66]) by mx1.freebsd.org (Postfix) with ESMTP id 857528FC17 for ; Mon, 18 Apr 2011 13:25:18 +0000 (UTC) Received: from triton.sigsegv.be ([94.225.212.114]) by brigitte.telenet-ops.be with bizsmtp id Z1RG1g00F2UfDsW0G1RGDQ; Mon, 18 Apr 2011 15:25:17 +0200 Received: from nereid (nereid.neptune.sigsegv.be [IPv6:2001:470:c8f4:0:200:ff:fe00:8]) by triton.sigsegv.be (Postfix) with SMTP id 68F291C1B2; Mon, 18 Apr 2011 15:25:15 +0200 (CEST) Received: by nereid (sSMTP sendmail emulation); Mon, 18 Apr 2011 15:25:15 +0200 Date: Mon, 18 Apr 2011 15:25:13 +0200 From: Kristof Provost To: Nigel Roberts Message-ID: <20110418132513.GD12608@nereid> References: <20110322154505.GH1351@nereid> <20110418114015.GA4277@snippy.nobiscuit.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20110418114015.GA4277@snippy.nobiscuit.com> X-PGP-Fingerprint: E114 D9EA 909E D469 8F57 17A5 7D15 91C6 9EFA F286 User-Agent: Mutt/1.5.20 (2009-06-14) Cc: freebsd-arm@freebsd.org Subject: Re: Iomega iConnect and FreeBSD (kirkwood) X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Porting FreeBSD to the StrongARM Processor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Apr 2011 13:25:19 -0000 On 2011-04-18 11:40:15 (+0000), Nigel Roberts wrote: > On Tue, 22 Mar 2011 at 16:45:05 +0100, Kristof Provost wrote: > > > I'm not familiar with that platform, but I remember seeing a very > > similar error when I was playing with an Orion based board. > > The driver should be the same (mge). > > The panic occurs because the cleanup code is incorrect. This problem is > > fixed in current I think. > > > > In this case you probably don't need to worry about the cleanup code > > though. It's only triggered when the PHY is not found. > > If you can fix the PHY detection you won't run into the panic any more. > > In 8.2 mge assumes a static mapping between interface number and PHY > > address (i.e. PHY address = interface number (0 here) + 8). > > You can overrule the offset by defining MII_ADDRESS_BASE. > > Of course, you'll need to know the correct offset first. > > I'm also trying to get FreeBSD working on an Iomega device (an IX2-200) > and the issue is not that the address for the PHY is wrong, it's that the > first mge MAC doesn't actually have a PHY attached. Only the second MAC > has a PHY (I've checked on the PCB and have pics for the curious). In > Linux, only eth1 is usable, although eth0 is detected. Okay, That's going to trigger the same issue. > I'd really like to get this working in FreeBSD-STABLE. Can someone please > point me to where the cleanup code has been fixed in CURRENT so that I can > have a go at figuring out a patch? I also had a go at getting > FreeBSD-CURRENT working, but it wouldn't even get to the copyright > message on boot. I'm wondering if I got the fdt config wrong, so I am > going to check on that. Take a look at r201198. It ensures that the interrupt handlers are not cleaned up if they haven't been registered in the first place. That should prevent the driver from panicking when it doesn't find a PHY. Regards, Kristof From owner-freebsd-arm@FreeBSD.ORG Mon Apr 18 19:00:24 2011 Return-Path: Delivered-To: freebsd-arm@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D5163106568B for ; Mon, 18 Apr 2011 19:00:24 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id C2A5E8FC14 for ; Mon, 18 Apr 2011 19:00:24 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id p3IJ0Odc079648 for ; Mon, 18 Apr 2011 19:00:24 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p3IJ0OWs079642; Mon, 18 Apr 2011 19:00:24 GMT (envelope-from gnats) Date: Mon, 18 Apr 2011 19:00:24 GMT Message-Id: <201104181900.p3IJ0OWs079642@freefall.freebsd.org> To: freebsd-arm@FreeBSD.org From: Ian Lepore Cc: Subject: Re: arm/155214: [patch] MMC/SD IO slow on Atmel ARM with modern large SD cards X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Ian Lepore List-Id: Porting FreeBSD to the StrongARM Processor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Apr 2011 19:00:24 -0000 The following reply was made to PR arm/155214; it has been noted by GNATS. From: Ian Lepore To: bug-followup@FreeBSD.org Cc: Subject: Re: arm/155214: [patch] MMC/SD IO slow on Atmel ARM with modern large SD cards Date: Mon, 18 Apr 2011 12:45:28 -0600 I have an updated patch for this which includes better error handling, and better read performance (mainly by splitting large IO requests into two DMA operations and doing the byte-swapping for the first half while the second half is still on the wire from the card). It also has more comments about what works and what doesn't (ex: 30mhz 4-bit transfers when USB Host mode is also enabled). I don't see any straightforward way on the PR page to nuke the original patch and supply a replacement. What's the best way to handle that? -- Ian From owner-freebsd-arm@FreeBSD.ORG Mon Apr 18 20:07:30 2011 Return-Path: Delivered-To: freebsd-arm@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 4D6C010657C4 for ; Mon, 18 Apr 2011 20:07:30 +0000 (UTC) (envelope-from imp@bsdimp.com) Received: from harmony.bsdimp.com (bsdimp.com [199.45.160.85]) by mx1.freebsd.org (Postfix) with ESMTP id 0A5A18FC21 for ; Mon, 18 Apr 2011 20:07:29 +0000 (UTC) Received: from [10.30.101.53] ([209.117.142.2]) (authenticated bits=0) by harmony.bsdimp.com (8.14.4/8.14.3) with ESMTP id p3IK2CPv041974 (version=TLSv1/SSLv3 cipher=DHE-DSS-AES128-SHA bits=128 verify=NO); Mon, 18 Apr 2011 14:02:50 -0600 (MDT) (envelope-from imp@bsdimp.com) Mime-Version: 1.0 (Apple Message framework v1084) Content-Type: text/plain; charset=us-ascii From: Warner Losh In-Reply-To: <201104181900.p3IJ0OWs079642@freefall.freebsd.org> Date: Mon, 18 Apr 2011 14:02:52 -0600 Content-Transfer-Encoding: 7bit Message-Id: <2578F555-AFF8-405D-ACA2-914A765FE4BC@bsdimp.com> References: <201104181900.p3IJ0OWs079642@freefall.freebsd.org> To: Ian Lepore X-Mailer: Apple Mail (2.1084) X-Greylist: Sender succeeded SMTP AUTH, not delayed by milter-greylist-4.0.1 (harmony.bsdimp.com [10.0.0.6]); Mon, 18 Apr 2011 14:02:51 -0600 (MDT) Cc: freebsd-arm@FreeBSD.org Subject: Re: arm/155214: [patch] MMC/SD IO slow on Atmel ARM with modern large SD cards X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Porting FreeBSD to the StrongARM Processor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 18 Apr 2011 20:07:30 -0000 On Apr 18, 2011, at 1:00 PM, Ian Lepore wrote: > The following reply was made to PR arm/155214; it has been noted by GNATS. > > From: Ian Lepore > To: bug-followup@FreeBSD.org > Cc: > Subject: Re: arm/155214: [patch] MMC/SD IO slow on Atmel ARM with modern > large SD cards > Date: Mon, 18 Apr 2011 12:45:28 -0600 > > I have an updated patch for this which includes better error handling, > and better read performance (mainly by splitting large IO requests into > two DMA operations and doing the byte-swapping for the first half while > the second half is still on the wire from the card). It also has more > comments about what works and what doesn't (ex: 30mhz 4-bit transfers > when USB Host mode is also enabled). > > I don't see any straightforward way on the PR page to nuke the original > patch and supply a replacement. What's the best way to handle that? Just submit the patch as a followup. Warner From owner-freebsd-arm@FreeBSD.ORG Tue Apr 19 15:40:03 2011 Return-Path: Delivered-To: freebsd-arm@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id EF0C8106566B for ; Tue, 19 Apr 2011 15:40:03 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id BB8AE8FC15 for ; Tue, 19 Apr 2011 15:40:03 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id p3JFe31f085383 for ; Tue, 19 Apr 2011 15:40:03 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p3JFe3jq085382; Tue, 19 Apr 2011 15:40:03 GMT (envelope-from gnats) Resent-Date: Tue, 19 Apr 2011 15:40:03 GMT Resent-Message-Id: <201104191540.p3JFe3jq085382@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-arm@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Ian Lepore Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 8967F106564A for ; Tue, 19 Apr 2011 15:33:40 +0000 (UTC) (envelope-from ilepore@damnhippie.dyndns.org) Received: from qmta01.emeryville.ca.mail.comcast.net (qmta01.emeryville.ca.mail.comcast.net [76.96.30.16]) by mx1.freebsd.org (Postfix) with ESMTP id 6E78B8FC0C for ; Tue, 19 Apr 2011 15:33:40 +0000 (UTC) Received: from omta21.emeryville.ca.mail.comcast.net ([76.96.30.88]) by qmta01.emeryville.ca.mail.comcast.net with comcast id ZSVp1g0071u4NiLA1TLWNE; Tue, 19 Apr 2011 15:20:30 +0000 Received: from damnhippie.dyndns.org ([24.8.232.202]) by omta21.emeryville.ca.mail.comcast.net with comcast id ZTLU1g01M4NgCEG8hTLVHb; Tue, 19 Apr 2011 15:20:29 +0000 Received: from revolution.hippie.lan (revolution.hippie.lan [172.22.42.240]) by damnhippie.dyndns.org (8.14.3/8.14.3) with ESMTP id p3JFKRku067915 for ; Tue, 19 Apr 2011 09:20:27 -0600 (MDT) (envelope-from ilepore@damnhippie.dyndns.org) Received: (from ilepore@localhost) by revolution.hippie.lan (8.14.4/8.14.4/Submit) id p3JFKQta028382; Tue, 19 Apr 2011 09:20:26 -0600 (MDT) (envelope-from ilepore) Message-Id: <201104191520.p3JFKQta028382@revolution.hippie.lan> Date: Tue, 19 Apr 2011 09:20:26 -0600 (MDT) From: Ian Lepore To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Cc: Subject: arm/156496: [patch] Minor bugfixes and enhancements to mmc and mmcsd drivers X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Ian Lepore List-Id: Porting FreeBSD to the StrongARM Processor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 19 Apr 2011 15:40:04 -0000 >Number: 156496 >Category: arm >Synopsis: [patch] Minor bugfixes and enhancements to mmc and mmcsd drivers >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-arm >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Tue Apr 19 15:40:03 UTC 2011 >Closed-Date: >Last-Modified: >Originator: Ian Lepore >Release: FreeBSD 8.2-RC3 arm >Organization: none >Environment: FreeBSD dvb 8.2-RC3 FreeBSD 8.2-RC3 #49: Tue Feb 15 22:52:14 UTC 2011 root@revolution.hippie.lan:/usr/obj/arm/usr/src/sys/DVB arm >Description: This applies several fixes and minor enhancements to the mmc and mmcsd drivers. Fixes: - When switching to 4-bit operation, send a SET_CLR_CARD_DETECT command to disconnect the card-detect pullup resistor from the DAT3 line before sending the SET_BUS_WIDTH command. - Add the missing "reserved" zero entry to the mantissa table used to decode various CSD fields. This was causing SD cards to report that they could run at 30mhz instead of the maximum 25mhz mandated in the spec. Enhancements: - At the MMC layer, format various info from the CID into a string that uniquely identifies the card instance (manufacturer number, serial number, product name and revision,etc). Export it as an instance variable. - At the MMCSD layer, display the formatted card id string, and also report the clock speed of the hardware (not the card's max speed), and the number of bits and number of blocks per transfer. It comes out like this now: mmcsd0: 968MB at mmc0 22.5MHz/4bit/128-block These diffs were generated against code from FreeBSD 9 as it existed on March 15 2011 (re-tested on April 19 2011). These changes have been tested on ARM at91rm9200 hardware. I don't have access to an sdhci controller for testing, but since these changes don't affect the mmc<->underlying-bridge-hardware interface in any way, I don't anticipate any problems. Work sponsored by: Symmetricom, Inc. >How-To-Repeat: >Fix: --- patch-mmcsd begins here --- --- sys/dev/mmc/mmc.c 2011-03-15 08:45:51.000000000 -0600 +++ sys/dev/mmc2/mmc.c 2011-03-15 08:54:38.000000000 -0600 @@ -101,6 +101,7 @@ uint32_t tran_speed; /* Max speed in normal mode */ uint32_t hs_tran_speed; /* Max speed in high speed mode */ uint32_t erase_sector; /* Card native erase sector size */ + char card_id_string[64];/* Formatted CID info (serial, mfg, etc) */ }; #define CMD_RETRIES 3 @@ -606,19 +607,26 @@ if (mmcbr_get_mode(sc->dev) == mode_sd) { memset(&cmd, 0, sizeof(struct mmc_command)); - cmd.opcode = ACMD_SET_BUS_WIDTH; + cmd.opcode = ACMD_SET_CLR_CARD_DETECT; cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; - switch (width) { - case bus_width_1: - cmd.arg = SD_BUS_WIDTH_1; - break; - case bus_width_4: - cmd.arg = SD_BUS_WIDTH_4; - break; - default: - return (MMC_ERR_INVALID); - } + cmd.arg = SD_CLR_CARD_DETECT; err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES); + if (err == 0) { + memset(&cmd, 0, sizeof(struct mmc_command)); + cmd.opcode = ACMD_SET_BUS_WIDTH; + cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; + switch (width) { + case bus_width_1: + cmd.arg = SD_BUS_WIDTH_1; + break; + case bus_width_4: + cmd.arg = SD_BUS_WIDTH_4; + break; + default: + return (MMC_ERR_INVALID); + } + err = mmc_wait_for_app_cmd(sc, rca, &cmd, CMD_RETRIES); + } } else { switch (width) { case bus_width_1: @@ -788,11 +796,45 @@ cid->mdt_year = mmc_get_bits(raw_cid, 128, 8, 4) + 1997; } +static void +mmc_format_card_id_string(struct mmc_ivars * ivar) +{ + char oidstr[8]; + uint8_t c1 = (ivar->cid.oid >> 8) & 0x0FF; + uint8_t c2 = ivar->cid.oid & 0x0FF; + + /* Format a card ID string for use by the mmcsd driver, it's what + * appears between the <> in the following: + * + * mmcsd0: 968MB at mmc0 + * 22.5MHz/4bit/128-block + * + * The card_id_string in mmc_ivars is currently allocated as 64 bytes, + * and our max formatted length is currently 55 bytes if every field + * contains the largest value. + * + * Sometimes the oid is two printable ascii chars; when it's not, + * format it as 0xnnnn instead. + */ + + if (c1 > 0x1F && c1 < 0x7F && c2 > 0x1F && c2 < 0x7F) + snprintf(oidstr, sizeof(oidstr), "%c%c", c1, c2); + else + snprintf(oidstr, sizeof(oidstr), "0x%04X", ivar->cid.oid); + + snprintf(ivar->card_id_string, sizeof(ivar->card_id_string), + "%s%s %s %d.%d SN %d Mfg %02d/%04d by %d %s", + ivar->mode == mode_sd ? "SD" : "MMC", ivar->high_cap ? "HC" : "", + ivar->cid.pnm, ivar->cid.prv >> 4, ivar->cid.prv & 0x0f, + ivar->cid.psn, ivar->cid.mdt_month, ivar->cid.mdt_year, + ivar->cid.mid, oidstr); +} + static const int exp[8] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 }; static const int mant[16] = { - 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 + 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; static const int cur_min[8] = { 500, 1000, 5000, 10000, 25000, 35000, 60000, 100000 @@ -1080,13 +1109,8 @@ { device_printf(dev, "Card at relative address %d%s:\n", ivar->rca, newcard ? " added" : ""); - device_printf(dev, " card: %s%s (0x%x/0x%x/\"%s\" rev %d.%d " - "m/d %02d.%04d s/n %08x)\n", - ivar->mode == mode_sd ? "SD" : "MMC", - ivar->high_cap ? " High Capacity" : "", - ivar->cid.mid, ivar->cid.oid, - ivar->cid.pnm, ivar->cid.prv >> 4, ivar->cid.prv & 0x0f, - ivar->cid.mdt_month, ivar->cid.mdt_year, ivar->cid.psn); + device_printf(dev, " card: %s\n", + ivar->card_id_string); device_printf(dev, " bus: %ubit, %uMHz%s\n", (ivar->bus_width == bus_width_1 ? 1 : (ivar->bus_width == bus_width_4 ? 4 : 8)), @@ -1188,6 +1212,7 @@ if ((mmcbr_get_caps(sc->dev) & MMC_CAP_4_BIT_DATA) && (ivar->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) ivar->bus_width = bus_width_4; + mmc_format_card_id_string(ivar); if (bootverbose || mmc_debug) mmc_log_card(sc->dev, ivar, newcard); if (newcard) { @@ -1245,6 +1270,7 @@ ivar->bus_width = bus_width_1; ivar->timing = bus_timing_normal; } + mmc_format_card_id_string(ivar); if (bootverbose || mmc_debug) mmc_log_card(sc->dev, ivar, newcard); if (newcard) { @@ -1477,6 +1503,9 @@ case MMC_IVAR_MAX_DATA: *(int *)result = mmcbr_get_max_data(bus); break; + case MMC_IVAR_CARD_ID_STRING: + *(char **)result = ivar->card_id_string; + break; } return (0); } --- sys/dev/mmc/mmcsd.c 2011-03-15 08:45:51.000000000 -0600 +++ sys/dev/mmc2/mmcsd.c 2011-03-15 07:29:59.000000000 -0600 @@ -68,9 +68,17 @@ #include #include - +#include #include "mmcbus_if.h" +/* The kthread_* functions were renamed to kproc_* in FreeBSD 8; + * these defines help backport this code to earlier versions. + */ +#if __FreeBSD__ < 8 +#define kproc_create kthread_create +#define kproc_exit kthread_exit +#endif + struct mmcsd_softc { device_t dev; struct mtx sc_mtx; @@ -95,7 +103,6 @@ off_t offset, size_t length); static void mmcsd_task(void *arg); -static const char *mmcsd_card_name(device_t dev); static int mmcsd_bus_bit_width(device_t dev); #define MMCSD_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) @@ -122,6 +129,8 @@ struct mmcsd_softc *sc; struct disk *d; intmax_t mb; + uint32_t speed; + uint32_t maxblocks; char unit; sc = device_get_softc(dev); @@ -157,11 +166,21 @@ unit = 'G'; mb /= 1024; } - device_printf(dev, "%ju%cB <%s Memory Card>%s at %s %dMHz/%dbit\n", - mb, unit, mmcsd_card_name(dev), + /* Report the clock speed of the underlying hardware, which might be + * different than what the card reports due to hardware limitations. + * Report how many blocks the hardware transfers at once, but clip the + * number to MAXPHYS since the system won't initiate bigger transfers. + */ + speed = mmcbr_get_clock(device_get_parent(dev)); + maxblocks = mmc_get_max_data(dev); + if (maxblocks > MAXPHYS) + maxblocks = MAXPHYS; + device_printf(dev, "%ju%cB <%s>%s at %s %d.%01dMHz/%dbit/%d-block\n", + mb, unit, mmc_get_card_id_string(dev), mmc_get_read_only(dev) ? " (read-only)" : "", device_get_nameunit(device_get_parent(dev)), - mmc_get_tran_speed(dev) / 1000000, mmcsd_bus_bit_width(dev)); + speed / 1000000, (speed / 100000) % 10, + mmcsd_bus_bit_width(dev), maxblocks); disk_create(d, DISK_VERSION); bioq_init(&sc->bio_queue); @@ -500,16 +519,6 @@ kproc_exit(0); } -static const char * -mmcsd_card_name(device_t dev) -{ - if (mmc_get_card_type(dev) == mode_mmc) - return ("MMC"); - if (mmc_get_high_cap(dev)) - return ("SDHC"); - return ("SD"); -} - static int mmcsd_bus_bit_width(device_t dev) { --- sys/dev/mmc/mmcreg.h 2011-03-15 08:45:51.000000000 -0600 +++ sys/dev/mmc2/mmcreg.h 2011-03-14 18:10:10.000000000 -0600 @@ -330,6 +330,9 @@ #define SD_SWITCH_HS_MODE 1 #define SD_SWITCH_NOCHANGE 0xF +#define SD_CLR_CARD_DETECT 0 +#define SD_SET_CARD_DETECT 1 + #define SD_MAX_HS 50000000 /* OCR bits */ --- sys/dev/mmc/mmcvar.h 2011-03-15 08:45:51.000000000 -0600 +++ sys/dev/mmc2/mmcvar.h 2011-03-15 08:13:20.000000000 -0600 @@ -69,6 +69,7 @@ MMC_IVAR_BUS_WIDTH, MMC_IVAR_ERASE_SECTOR, MMC_IVAR_MAX_DATA, + MMC_IVAR_CARD_ID_STRING, // MMC_IVAR_, }; @@ -89,5 +90,6 @@ MMC_ACCESSOR(bus_width, BUS_WIDTH, int) MMC_ACCESSOR(erase_sector, ERASE_SECTOR, int) MMC_ACCESSOR(max_data, MAX_DATA, int) +MMC_ACCESSOR(card_id_string, CARD_ID_STRING, const char *) #endif /* DEV_MMC_MMCVAR_H */ --- patch-mmcsd ends here --- >Release-Note: >Audit-Trail: >Unformatted: From owner-freebsd-arm@FreeBSD.ORG Tue Apr 19 18:10:11 2011 Return-Path: Delivered-To: freebsd-arm@hub.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2D6DC1065678 for ; Tue, 19 Apr 2011 18:10:11 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:4f8:fff6::28]) by mx1.freebsd.org (Postfix) with ESMTP id 189178FC0A for ; Tue, 19 Apr 2011 18:10:11 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.4/8.14.4) with ESMTP id p3JIABF3019632 for ; Tue, 19 Apr 2011 18:10:11 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.4/8.14.4/Submit) id p3JIAB8e019631; Tue, 19 Apr 2011 18:10:11 GMT (envelope-from gnats) Date: Tue, 19 Apr 2011 18:10:11 GMT Message-Id: <201104191810.p3JIAB8e019631@freefall.freebsd.org> To: freebsd-arm@FreeBSD.org From: Ian Lepore Cc: Subject: Re: arm/155214: [patch] MMC/SD IO slow on Atmel ARM with modern large SD cards (updated patch) X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: Ian Lepore List-Id: Porting FreeBSD to the StrongARM Processor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 19 Apr 2011 18:10:11 -0000 The following reply was made to PR arm/155214; it has been noted by GNATS. From: Ian Lepore To: bug-followup@FreeBSD.org, freebsd@damnhippie.dyndns.org Cc: Subject: Re: arm/155214: [patch] MMC/SD IO slow on Atmel ARM with modern large SD cards (updated patch) Date: Tue, 19 Apr 2011 12:06:43 -0600 Index: sys/arm/at91/at91_mci.c =================================================================== --- sys/arm/at91/at91_mci.c.cvs_v1.18 2011-03-30 08:30:18.000000000 -0600 +++ sys/arm/at91/at91_mci.c 2011-04-18 12:04:55.000000000 -0600 @@ -67,7 +67,60 @@ #include "opt_at91.h" -#define BBSZ 512 +/* About running the MCI bus at 30mhz... + * + * Historically, the MCI bus has been run at 30mhz on systems with a 60mhz + * master clock, due to a bug in the mantissa table in dev/mmc.c making it + * appear that the card's max speed was always 30mhz. Fixing that bug causes + * the mmc driver to request a 25mhz clock (as it should) and the logic in + * at91_mci_update_ios() picks the highest speed that doesn't exceed that limit. + * With a 60mhz MCK that would be 15mhz, and that's a real performance buzzkill + * when you've been getting away with 30mhz all along. + * + * By defining AT91_MCI_USE_30MHZ (or setting the 30mhz=1 device hint or sysctl) + * you can enable logic in at91_mci_update_ios() to set the mci bus to 30mhz + * when MCK is 60mhz and the requested speed is 25mhz. This appears to work on + * virtually all SD cards, since it is what this driver has been doing by + * accident since day one. I've seen modern SD cards run at 45mhz/1-bit in + * standard mode (high speed mode enable commands not sent) without problems. + * + * Speaking of high-speed mode, the rm9200 manual says the MCI device supports + * the SD v1.0 specification and can run up to 50mhz. This is interesting in + * that the SD v1.0 spec caps the speed at 25mhz; high speed mode was added in + * the v1.10 spec. Furthermore, high speed mode doesn't just crank up the + * clock, it alters the signal timing. The rm9200 MCI device doesn't support + * these altered timings. So while speeds over 25mhz may work, they only work + * in what the SD spec calls "default" speed mode, and it amounts to violating + * the spec by overclocking the bus. + * + * If you also enable 4-wire mode it's possible the 30mhz transfers will fail. + * If you have the USB host device and OHCI driver enabled it's g'teed to fail + * (I get intermittant overrun and underrun errors even at 15mhz 4-wire with + * OHCI). Note that you don't even need to have usb devices attached to the + * system, the errors begin to occur as soon as the OHCI driver sets the + * register bit to enable periodic transfers. It appears (based on brief + * investigation) that the usb host controller uses so much ASB bandwidth that + * sometimes the DMA for MCI transfers doesn't get a bus grant in time and data + * gets dropped. Adding even a modicum of network activity changes the symptom + * from intermittant to very frequent. + */ + +#ifndef AT91_MCI_USE_30MHZ +#define AT91_MCI_USE_30MHZ 1 +#endif + +/* Allocate 2 bounce buffers, each being sized to half the system default + * physical IO size. That enables doing DFLTPHYS sized transfers at a time, + * with read transfers in particular being split into two operations so that we + * can overlap some of the byte-swapping needed due to the rm9200 erratum with + * the DMA for the second half of the transfer. + */ + +#define BBCOUNT 2 +#define BBSIZE (DFLTPHYS/BBCOUNT) +#define MAX_BLOCKS ((BBSIZE*BBCOUNT)/512) + +static int mci_debug; struct at91_mci_softc { void *intrhand; /* Interrupt handle */ @@ -75,21 +128,26 @@ int sc_cap; #define CAP_HAS_4WIRE 1 /* Has 4 wire bus */ #define CAP_NEEDS_BYTESWAP 2 /* broken hardware needing bounce */ - int flags; int has_4wire; -#define CMD_STARTED 1 -#define STOP_STARTED 2 + int use_30mhz; + int flags; +#define PENDING_CMD 0x01 +#define PENDING_STOP 0x02 +#define CMD_MULTIREAD 0x10 +#define CMD_MULTIWRITE 0x20 struct resource *irq_res; /* IRQ resource */ struct resource *mem_res; /* Memory resource */ struct mtx sc_mtx; bus_dma_tag_t dmatag; - bus_dmamap_t map; - int mapped; struct mmc_host host; int bus_busy; struct mmc_request *req; struct mmc_command *curcmd; - char bounce_buffer[BBSZ]; + bus_dmamap_t bbuf_map[BBCOUNT]; + char * bbuf_vaddr[BBCOUNT]; /* bounce bufs in KVA space */ + uint32_t bbuf_len[BBCOUNT]; /* len currently queued for bounce buf */ + uint32_t bbuf_curidx; /* which bbuf is the active DMA buffer */ + uint32_t xfer_offset; /* offset so far into caller's buf */ }; static inline uint32_t @@ -123,6 +181,47 @@ #define AT91_MCI_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); #define AT91_MCI_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); +static void +at91_bswap_buf(struct at91_mci_softc *sc, void * dptr, void * sptr, uint32_t memsize) +{ + uint32_t * dst = (uint32_t *)dptr; + uint32_t * src = (uint32_t *)sptr; + uint32_t i; + + /* If the hardware doesn't need byte-swapping, let bcopy() do the work. + */ + + if (!(sc->sc_cap & CAP_NEEDS_BYTESWAP)) { + bcopy(dptr, sptr, memsize); + return; + } + + /* Nice performance boost for slightly unrolling this loop. + * (But very little extra boost for further unrolling it.) + */ + + for (i = 0; i < memsize; i += 16) { + *dst++ = bswap32(*src++); + *dst++ = bswap32(*src++); + *dst++ = bswap32(*src++); + *dst++ = bswap32(*src++); + } + + /* Mop up the last 1-3 words, if any. */ + + for (i = 0; i < (memsize & 0x0F); i += 4) { + *dst++ = bswap32(*src++); + } +} + +static void +at91_mci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) +{ + if (error != 0) + return; + *(bus_addr_t *)arg = segs[0].ds_addr; +} + static void at91_mci_pdc_disable(struct at91_mci_softc *sc) { @@ -137,15 +236,57 @@ WR4(sc, PDC_TNCR, 0); } +/* Reset the controller, then restore most of the current state. + * + * This is called after detecting an error. It's also called after stopping a + * multi-block write, to un-wedge the device so that it will handle the NOTBUSY + * signal correctly. See comments in at91_mci_stop_done() for more details. + */ +static void at91_mci_reset(struct at91_mci_softc *sc) +{ + uint32_t mr; + uint32_t sdcr; + uint32_t dtor; + uint32_t imr; + + at91_mci_pdc_disable(sc); + + /* save current state */ + + imr = RD4(sc, MCI_IMR); + mr = RD4(sc, MCI_MR) & 0x7fff; + sdcr = RD4(sc, MCI_SDCR); + dtor = RD4(sc, MCI_DTOR); + + /* reset the controller */ + + WR4(sc, MCI_IDR, 0xffffffff); + WR4(sc, MCI_CR, MCI_CR_MCIDIS | MCI_CR_SWRST); + + /* restore state */ + + WR4(sc, MCI_CR, MCI_CR_MCIEN|MCI_CR_PWSEN); + WR4(sc, MCI_MR, mr); + WR4(sc, MCI_SDCR, sdcr); + WR4(sc, MCI_DTOR, dtor); + WR4(sc, MCI_IER, imr); + + /* Make sure sdio interrupts will fire. Not sure why reading + * SR ensures that, but this is in the linux driver. + */ + + RD4(sc, MCI_SR); +} + static void at91_mci_init(device_t dev) { struct at91_mci_softc *sc = device_get_softc(dev); - WR4(sc, MCI_CR, MCI_CR_MCIEN); /* Enable controller */ + WR4(sc, MCI_CR, MCI_CR_MCIDIS | MCI_CR_SWRST); /* Put the device into reset */ WR4(sc, MCI_IDR, 0xffffffff); /* Turn off interrupts */ WR4(sc, MCI_DTOR, MCI_DTOR_DTOMUL_1M | 1); - WR4(sc, MCI_MR, 0x834a); // XXX GROSS HACK FROM LINUX + WR4(sc, MCI_MR, 0x834a); // set PDCMODE, PWSDIV=3, CLKDIV=75 #ifndef AT91_MCI_SLOT_B WR4(sc, MCI_SDCR, 0); /* SLOT A, 1 bit bus */ #else @@ -153,6 +294,11 @@ * a two slot card that we know of. XXX */ WR4(sc, MCI_SDCR, 1); /* SLOT B, 1 bit bus */ #endif + /* Enable controller, including power-save. The slower clock of + * the power-save mode is only in effect when there is no transfer in + * progress, so it can be left in this mode all the time. + */ + WR4(sc, MCI_CR, MCI_CR_MCIEN|MCI_CR_PWSEN); } static void @@ -167,8 +313,8 @@ static int at91_mci_probe(device_t dev) -{ +{ device_set_desc(dev, "MCI mmc/sd host bridge"); return (0); } @@ -180,6 +326,7 @@ struct sysctl_ctx_list *sctx; struct sysctl_oid *soid; device_t child; + int i; int err; sc->dev = dev; @@ -193,48 +340,100 @@ AT91_MCI_LOCK_INIT(sc); - /* - * Allocate DMA tags and maps + at91_mci_fini(dev); + at91_mci_init(dev); + + /* Allocate DMA tags and maps and bounce buffers. + * + * The parms in the tag_create call cause the dmamem_alloc call to + * create each bounce buffer as a single contiguous buffer of BBSIZE + * bytes aligned to a 4096 byte boundary. + * + * Do not use DMA_COHERENT for these buffers because that maps the + * memory as non-cachable, which prevents cache line burst fills/writes, + * which is something we need since we're trying to overlap the + * byte-swapping with the DMA operations. */ - err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, - BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, MAXPHYS, 1, - MAXPHYS, BUS_DMA_ALLOCNOW, NULL, NULL, &sc->dmatag); - if (err != 0) - goto out; - err = bus_dmamap_create(sc->dmatag, 0, &sc->map); + err = bus_dma_tag_create(bus_get_dma_tag(dev), 4096, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + BBSIZE, 1, MAXPHYS, 0, NULL, NULL, &sc->dmatag); if (err != 0) goto out; - at91_mci_fini(dev); - at91_mci_init(dev); + for (i = 0; i < BBCOUNT; ++i) { + err = bus_dmamem_alloc(sc->dmatag, (void **)&sc->bbuf_vaddr[i], + BUS_DMA_NOWAIT, &sc->bbuf_map[i]); + if (err != 0) + goto out; + } /* * Activate the interrupt */ - err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, + err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_BIO | INTR_MPSAFE, NULL, at91_mci_intr, sc, &sc->intrhand); if (err) { AT91_MCI_LOCK_DESTROY(sc); goto out; } + /* Allow 4-wire to be initially set via #define. + * Allow a device hint to override that. + * Allow a sysctl to override that. + */ + +#if defined(AT91_MCI_HAS_4WIRE) && AT91_MCI_HAS_4WIRE != 0 + sc->has_4wire = 1; +#else + sc->has_4wire = 0; +#endif + + resource_int_value(device_get_name(dev), device_get_unit(dev), + "4wire", &sc->has_4wire); + sctx = device_get_sysctl_ctx(dev); soid = device_get_sysctl_tree(dev); SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "4wire", CTLFLAG_RW, &sc->has_4wire, 0, "has 4 wire SD Card bus"); -#ifdef AT91_MCI_HAS_4WIRE - sc->has_4wire = 1; -#endif if (sc->has_4wire) sc->sc_cap |= CAP_HAS_4WIRE; - sc->host.f_min = at91_master_clock / 512; + /* Allow use_30mhz to be initially set via #define. + * Allow a device hint to override that. + * Allow a sysctl to override that. + */ + +#if defined(AT91_MCI_USE_30MHZ) && AT91_MCI_USE_30MHZ != 0 + sc->use_30mhz = 1; +#else + sc->use_30mhz = 0; +#endif + + resource_int_value(device_get_name(dev), device_get_unit(dev), + "30mhz", &sc->use_30mhz); + + sctx = device_get_sysctl_ctx(dev); + soid = device_get_sysctl_tree(dev); + SYSCTL_ADD_UINT(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "30mhz", + CTLFLAG_RW, &sc->use_30mhz, 0, "use 30mhz clock for 25mhz request"); + + /* Our real min freq is master_clock/512, but upper driver layers are + * going to set the min speed during card discovery, and the right speed + * for that is 400khz, so advertise a safe value just under that. + * + * For max speed, while the rm9200 manual says the max is 50mhz, it also + * says it supports only the SD v1.0 spec, which means the real limit is + * 25mhz. On the other hand, historical use has been to slightly violate + * the standard by running the bus at 30mhz. For more information on + * that, see the comments at the top of this file. + */ + sc->host.f_min = 375000; sc->host.f_max = at91_master_clock / 2; - if (sc->host.f_max > 50000000) - sc->host.f_max = 50000000; /* Limit to 50MHz */ + if (sc->host.f_max > 25000000) + sc->host.f_max = 25000000; sc->host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340; sc->host.caps = 0; @@ -252,8 +451,15 @@ static int at91_mci_detach(device_t dev) { + struct at91_mci_softc *sc = device_get_softc(dev); + at91_mci_fini(dev); at91_mci_deactivate(dev); + + bus_dmamem_free(sc->dmatag, sc->bbuf_vaddr[0], sc->bbuf_map[0]); + bus_dmamem_free(sc->dmatag, sc->bbuf_vaddr[1], sc->bbuf_map[1]); + bus_dma_tag_destroy(sc->dmatag); + return (EBUSY); /* XXX */ } @@ -293,7 +499,7 @@ sc->intrhand = 0; bus_generic_detach(sc->dev); if (sc->mem_res) - bus_release_resource(dev, SYS_RES_IOPORT, + bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->mem_res), sc->mem_res); sc->mem_res = 0; if (sc->irq_res) @@ -303,14 +509,6 @@ return; } -static void -at91_mci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) -{ - if (error != 0) - return; - *(bus_addr_t *)arg = segs[0].ds_addr; -} - static int at91_mci_update_ios(device_t brdev, device_t reqdev) { @@ -322,16 +520,31 @@ sc = device_get_softc(brdev); host = &sc->host; ios = &host->ios; - // bus mode? + + /* Calculate our closest available clock speed that doesn't exceed the + * requested speed. + * + * If the master clock is running at 60mhz and the requested bus speed + * is 25mhz and the use_30mhz flag is on, set clkdiv to zero to get a + * 30mhz mci clock. See comments near the top of the file for more info. + * + * Whatever we come up with, store it back into ios->clock so that the + * upper layer drivers can report the actual speed of the bus. + */ + if (ios->clock == 0) { WR4(sc, MCI_CR, MCI_CR_MCIDIS); clkdiv = 0; } else { - WR4(sc, MCI_CR, MCI_CR_MCIEN); - if ((at91_master_clock % (ios->clock * 2)) == 0) + WR4(sc, MCI_CR, MCI_CR_MCIEN|MCI_CR_PWSEN); + if (sc->use_30mhz && at91_master_clock == 60000000 && + ios->clock == 25000000) + clkdiv = 0; + else if ((at91_master_clock % (ios->clock * 2)) == 0) clkdiv = ((at91_master_clock / ios->clock) / 2) - 1; else clkdiv = (at91_master_clock / ios->clock) / 2; + ios->clock = at91_master_clock / ((clkdiv+1) * 2); } if (ios->bus_width == bus_width_4) WR4(sc, MCI_SDCR, RD4(sc, MCI_SDCR) | MCI_SDCR_SDCBUS); @@ -346,137 +559,247 @@ static void at91_mci_start_cmd(struct at91_mci_softc *sc, struct mmc_command *cmd) { - uint32_t cmdr, ier = 0, mr; - uint32_t *src, *dst; - int i; + uint32_t cmdr, mr; struct mmc_data *data; - void *vaddr; - bus_addr_t paddr; sc->curcmd = cmd; data = cmd->data; - cmdr = cmd->opcode; /* XXX Upper layers don't always set this */ cmd->mrq = sc->req; + /* Begin setting up command register. */ + + cmdr = cmd->opcode; + + if (sc->host.ios.bus_mode == opendrain) + cmdr |= MCI_CMDR_OPDCMD; + + /* Set up response handling. Allow max timeout for responses. */ + if (MMC_RSP(cmd->flags) == MMC_RSP_NONE) cmdr |= MCI_CMDR_RSPTYP_NO; else { - /* Allow big timeout for responses */ cmdr |= MCI_CMDR_MAXLAT; if (cmd->flags & MMC_RSP_136) cmdr |= MCI_CMDR_RSPTYP_136; else cmdr |= MCI_CMDR_RSPTYP_48; } - if (cmd->opcode == MMC_STOP_TRANSMISSION) - cmdr |= MCI_CMDR_TRCMD_STOP; - if (sc->host.ios.bus_mode == opendrain) - cmdr |= MCI_CMDR_OPDCMD; - if (!data) { - // The no data case is fairly simple + + /* If there is no data transfer, just set up the right interrupt mask + * and start the command. + * + * The interrupt mask needs to be CMDRDY plus all non-data-transfer + * errors. It's important to leave the transfer-related errors out, to + * avoid spurious timeout or crc errors on a STOP command following a + * multiblock read. When a multiblock read is in progress, sending a + * STOP in the middle of a block occasionally triggers such errors, but + * we're totally disinterested in them because we've already gotten all + * the data we wanted without error before sending the STOP command. + */ + + if (data == NULL) { + uint32_t ier = MCI_SR_CMDRDY | + MCI_SR_RTOE | MCI_SR_RENDE | + MCI_SR_RCRCE | MCI_SR_RDIRE | MCI_SR_RINDE; + at91_mci_pdc_disable(sc); -// printf("CMDR %x ARGR %x\n", cmdr, cmd->arg); + + if (cmd->opcode == MMC_STOP_TRANSMISSION) + cmdr |= MCI_CMDR_TRCMD_STOP; + + /* Ignore response CRC on CMD2 and ACMD41, per standard. */ + + if (cmd->opcode == MMC_SEND_OP_COND || + cmd->opcode == ACMD_SD_SEND_OP_COND) + ier &= ~MCI_SR_RCRCE; + + if (mci_debug) + printf("CMDR %x (opcode %d) ARGR %x no data\n", + cmdr, cmd->opcode, cmd->arg); + WR4(sc, MCI_ARGR, cmd->arg); WR4(sc, MCI_CMDR, cmdr); - WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_CMDRDY); + WR4(sc, MCI_IDR, 0xffffffff); + WR4(sc, MCI_IER, ier); return; } + + /* There is data, set up the transfer-related parts of the command. */ + if (data->flags & MMC_DATA_READ) cmdr |= MCI_CMDR_TRDIR; + if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) cmdr |= MCI_CMDR_TRCMD_START; + if (data->flags & MMC_DATA_STREAM) cmdr |= MCI_CMDR_TRTYP_STREAM; - if (data->flags & MMC_DATA_MULTI) + else if (data->flags & MMC_DATA_MULTI) { cmdr |= MCI_CMDR_TRTYP_MULTIPLE; - // Set block size and turn on PDC mode for dma xfer and disable - // PDC until we're ready. - mr = RD4(sc, MCI_MR) & ~MCI_MR_BLKLEN; - WR4(sc, MCI_MR, mr | (data->len << 16) | MCI_MR_PDCMODE); - WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS); - if (cmdr & MCI_CMDR_TRCMD_START) { - if (cmdr & MCI_CMDR_TRDIR) - vaddr = cmd->data->data; - else { - /* Use bounce buffer even if we don't need - * byteswap, since buffer may straddle a page - * boundry, and we don't handle multi-segment - * transfers in hardware. - * (page issues seen from 'bsdlabel -w' which - * uses raw geom access to the volume). - * Greg Ansley (gja (at) ansley.com) - */ - vaddr = sc->bounce_buffer; - src = (uint32_t *)cmd->data->data; - dst = (uint32_t *)vaddr; - if (sc->sc_cap & CAP_NEEDS_BYTESWAP) { - for (i = 0; i < data->len / 4; i++) - dst[i] = bswap32(src[i]); - } else - memcpy(dst, src, data->len); - } - data->xfer_len = 0; - if (bus_dmamap_load(sc->dmatag, sc->map, vaddr, data->len, - at91_mci_getaddr, &paddr, 0) != 0) { - cmd->error = MMC_ERR_NO_MEMORY; - sc->req = NULL; - sc->curcmd = NULL; - cmd->mrq->done(cmd->mrq); - return; - } - sc->mapped++; - if (cmdr & MCI_CMDR_TRDIR) { - bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_PREREAD); - WR4(sc, PDC_RPR, paddr); - WR4(sc, PDC_RCR, data->len / 4); - ier = MCI_SR_ENDRX; - } else { - bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_PREWRITE); - WR4(sc, PDC_TPR, paddr); - WR4(sc, PDC_TCR, data->len / 4); - ier = MCI_SR_TXBUFE; - } + sc->flags |= (data->flags & MMC_DATA_READ) ? + CMD_MULTIREAD : CMD_MULTIWRITE; } -// printf("CMDR %x ARGR %x with data\n", cmdr, cmd->arg); - WR4(sc, MCI_ARGR, cmd->arg); - if (cmdr & MCI_CMDR_TRCMD_START) { - if (cmdr & MCI_CMDR_TRDIR) { + + /* Disable PDC until we're ready. + * + * Set block size and turn on PDC mode for dma xfer. + * Note that the block size is the smaller of the amount of data to be + * transferred, or 512 bytes. The 512 size is fixed by the standard; + * smaller blocks are possible, but never larger. + */ + + WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS); + + mr = RD4(sc,MCI_MR) & ~MCI_MR_BLKLEN; + mr |= min(data->len, 512) << 16; + WR4(sc, MCI_MR, mr | MCI_MR_PDCMODE|MCI_MR_PDCPADV); + + /* Set up DMA. + * + * Use bounce buffers even if we don't need to byteswap, because doing + * multi-block IO with large DMA buffers is way fast (compared to + * single-block IO), even after incurring the overhead of also copying + * from/to the caller's buffers (which may be in non-contiguous physical + * pages). + * + * In an ideal non-byteswap world we could create a dma tag that allows + * for discontiguous segments and do the IO directly from/to the + * caller's buffer(s), using ENDRX/ENDTX interrupts to chain the + * discontiguous buffers through the PDC. Someday. + * + * If a read is bigger than 2k, split it in half so that we can start + * byte-swapping the first half while the second half is on the wire. + * It would be best if we could split it into 8k chunks, but we can't + * always keep up with the byte-swapping due to other system activity, + * and if an RXBUFF interrupt happens while we're still handling the + * byte-swap from the prior buffer (IE, we haven't returned from + * handling the prior interrupt yet), then data will get dropped on the + * floor and we can't easily recover from that. The right fix for that + * would be to have the interrupt handling only keep the DMA flowing and + * enqueue filled buffers to be byte-swapped in a non-interrupt context. + * Even that won't work on the write side of things though; in that + * context we have to have all the data ready to go before starting the + * dma. + * + * XXX what about stream transfers? + */ + + sc->xfer_offset = 0; + sc->bbuf_curidx = 0; + + if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) { + uint32_t len; + uint32_t remaining = data->len; + bus_addr_t paddr; + int err; + + if (remaining > (BBCOUNT*BBSIZE)) + panic("IO read size exceeds MAXDATA\n"); + + if (data->flags & MMC_DATA_READ) { + if (remaining > 2048) + len = remaining / 2; + else + len = remaining; + err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[0], + sc->bbuf_vaddr[0], len, at91_mci_getaddr, + &paddr, BUS_DMA_NOWAIT); + if (err != 0) + panic("IO read dmamap_load failed\n"); + bus_dmamap_sync(sc->dmatag, sc->bbuf_map[0], + BUS_DMASYNC_PREREAD); + WR4(sc, PDC_RPR, paddr); + WR4(sc, PDC_RCR, len / 4); + sc->bbuf_len[0] = len; + remaining -= len; + if (remaining == 0) { + sc->bbuf_len[1] = 0; + } else { + len = remaining; + err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[1], + sc->bbuf_vaddr[1], len, at91_mci_getaddr, + &paddr, BUS_DMA_NOWAIT); + if (err != 0) + panic("IO read dmamap_load failed\n"); + bus_dmamap_sync(sc->dmatag, sc->bbuf_map[1], + BUS_DMASYNC_PREREAD); + WR4(sc, PDC_RNPR, paddr); + WR4(sc, PDC_RNCR, len / 4); + sc->bbuf_len[1] = len; + remaining -= len; + } WR4(sc, PDC_PTCR, PDC_PTCR_RXTEN); - WR4(sc, MCI_CMDR, cmdr); } else { - WR4(sc, MCI_CMDR, cmdr); - WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN); + len = min(BBSIZE, remaining); + at91_bswap_buf(sc, sc->bbuf_vaddr[0], data->data, len); + err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[0], + sc->bbuf_vaddr[0], len, at91_mci_getaddr, + &paddr, BUS_DMA_NOWAIT); + if (err != 0) + panic("IO write dmamap_load failed\n"); + bus_dmamap_sync(sc->dmatag, sc->bbuf_map[0], + BUS_DMASYNC_PREWRITE); + WR4(sc, PDC_TPR,paddr); + WR4(sc, PDC_TCR, len / 4); + sc->bbuf_len[0] = len; + remaining -= len; + if (remaining == 0) { + sc->bbuf_len[1] = 0; + } else { + len = remaining; + at91_bswap_buf(sc, sc->bbuf_vaddr[1], + ((char *)data->data)+BBSIZE, len); + err = bus_dmamap_load(sc->dmatag, sc->bbuf_map[1], + sc->bbuf_vaddr[1], len, at91_mci_getaddr, + &paddr, BUS_DMA_NOWAIT); + if (err != 0) + panic("IO write dmamap_load failed\n"); + bus_dmamap_sync(sc->dmatag, sc->bbuf_map[1], + BUS_DMASYNC_PREWRITE); + WR4(sc, PDC_TNPR, paddr); + WR4(sc, PDC_TNCR, len / 4); + sc->bbuf_len[1] = len; + remaining -= len; + } + /* do not enable PDC xfer until CMDRDY asserted */ } + data->xfer_len = 0; /* XXX what's this? appears to be unused. */ } - WR4(sc, MCI_IER, MCI_SR_ERROR | ier); + + if (mci_debug) + printf("CMDR %x (opcode %d) ARGR %x with data len %d\n", + cmdr, cmd->opcode, cmd->arg, cmd->data->len); + + WR4(sc, MCI_ARGR, cmd->arg); + WR4(sc, MCI_CMDR, cmdr); + WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_CMDRDY); } static void -at91_mci_start(struct at91_mci_softc *sc) +at91_mci_next_operation(struct at91_mci_softc *sc) { struct mmc_request *req; req = sc->req; if (req == NULL) return; - // assert locked - if (!(sc->flags & CMD_STARTED)) { - sc->flags |= CMD_STARTED; -// printf("Starting CMD\n"); + + if (sc->flags & PENDING_CMD) { + sc->flags &= ~PENDING_CMD; at91_mci_start_cmd(sc, req->cmd); return; - } - if (!(sc->flags & STOP_STARTED) && req->stop) { -// printf("Starting Stop\n"); - sc->flags |= STOP_STARTED; + } else if (sc->flags & PENDING_STOP) { + sc->flags &= ~PENDING_STOP; at91_mci_start_cmd(sc, req->stop); return; } - /* We must be done -- bad idea to do this while locked? */ + + WR4(sc, MCI_IDR, 0xffffffff); sc->req = NULL; sc->curcmd = NULL; + //printf("req done\n"); req->done(req); } @@ -486,16 +809,16 @@ struct at91_mci_softc *sc = device_get_softc(brdev); AT91_MCI_LOCK(sc); - // XXX do we want to be able to queue up multiple commands? - // XXX sounds like a good idea, but all protocols are sync, so - // XXX maybe the idea is naive... if (sc->req != NULL) { AT91_MCI_UNLOCK(sc); return (EBUSY); } + //printf("new req\n"); sc->req = req; - sc->flags = 0; - at91_mci_start(sc); + sc->flags = PENDING_CMD; + if (sc->req->stop) + sc->flags |= PENDING_STOP; + at91_mci_next_operation(sc); AT91_MCI_UNLOCK(sc); return (0); } @@ -533,120 +856,341 @@ } static void -at91_mci_read_done(struct at91_mci_softc *sc) +at91_mci_read_done(struct at91_mci_softc *sc, uint32_t sr) { - uint32_t *walker; - struct mmc_command *cmd; - int i, len; - - cmd = sc->curcmd; - bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_POSTREAD); - bus_dmamap_unload(sc->dmatag, sc->map); - sc->mapped--; - if (sc->sc_cap & CAP_NEEDS_BYTESWAP) { - walker = (uint32_t *)cmd->data->data; - len = cmd->data->len / 4; - for (i = 0; i < len; i++) - walker[i] = bswap32(walker[i]); - } - // Finish up the sequence... - WR4(sc, MCI_IDR, MCI_SR_ENDRX); - WR4(sc, MCI_IER, MCI_SR_RXBUFF); - WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS); + struct mmc_command *cmd = sc->curcmd; + char * dataptr = (char *)cmd->data->data; + uint32_t curidx = sc->bbuf_curidx; + uint32_t len = sc->bbuf_len[curidx]; + + /* We arrive here when a DMA transfer for a read is done, whether it's a + * single or multi-block read. + * + * We byte-swap the buffer that just completed, and if that is the last + * buffer that's part of this read then we move on to the next + * operation, otherwise we wait for another ENDRX for the next bufer. + */ + + bus_dmamap_sync(sc->dmatag, sc->bbuf_map[curidx], BUS_DMASYNC_POSTREAD); + bus_dmamap_unload(sc->dmatag, sc->bbuf_map[curidx]); + + at91_bswap_buf(sc, dataptr + sc->xfer_offset, sc->bbuf_vaddr[curidx], len); + + if (mci_debug) { + printf("read done sr %x curidx %d len %d xfer_offset %d\n", + sr, curidx, len, sc->xfer_offset); + } + + sc->xfer_offset += len; + sc->bbuf_curidx = !curidx; /* swap buffers */ + + /* If we've transferred all the data, move on to the next operation. + * + * If we're still transferring the last buffer, RNCR is already zero but + * we have to write a zero anyway to clear the ENDRX status so we don't + * re-interrupt until the last buffer is done. + */ + + if (sc->xfer_offset == cmd->data->len) { + WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS); + cmd->error = MMC_ERR_NONE; + at91_mci_next_operation(sc); + } else { + WR4(sc, PDC_RNCR, 0); + WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_ENDRX); + } } static void -at91_mci_xmit_done(struct at91_mci_softc *sc) +at91_mci_write_done(struct at91_mci_softc *sc, uint32_t sr) { - // Finish up the sequence... + struct mmc_command *cmd = sc->curcmd; + + /* We arrive here when the entire DMA transfer for a write is done, + * whether it's a single or multi-block write. If it's multi-block we + * have to immediately move on to the next operation which is to send + * the stop command. If it's a single-block transfer we need to wait + * for NOTBUSY, but if that's already asserted we can avoid another + * interrupt and just move on to completing the request right away. + */ + WR4(sc, PDC_PTCR, PDC_PTCR_RXTDIS | PDC_PTCR_TXTDIS); - WR4(sc, MCI_IDR, MCI_SR_TXBUFE); - WR4(sc, MCI_IER, MCI_SR_NOTBUSY); - bus_dmamap_sync(sc->dmatag, sc->map, BUS_DMASYNC_POSTWRITE); - bus_dmamap_unload(sc->dmatag, sc->map); - sc->mapped--; + + bus_dmamap_sync(sc->dmatag, sc->bbuf_map[sc->bbuf_curidx], BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->dmatag, sc->bbuf_map[sc->bbuf_curidx]); + + if ((cmd->data->flags & MMC_DATA_MULTI) || (sr & MCI_SR_NOTBUSY)) { + cmd->error = MMC_ERR_NONE; + at91_mci_next_operation(sc); + } else { + WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_NOTBUSY); + } +} + +static void +at91_mci_notbusy(struct at91_mci_softc *sc) +{ + struct mmc_command *cmd = sc->curcmd; + + /* We arrive here by either completion of a single-block write, or + * completion of the stop command that ended a multi-block write (and, I + * suppose, after a card-select or erase, but I haven't tested those). + * Anyway, we're done and it's time to move on to the next command. + */ + + cmd->error = MMC_ERR_NONE; + at91_mci_next_operation(sc); +} + +static void +at91_mci_stop_done(struct at91_mci_softc *sc, uint32_t sr) +{ + struct mmc_command *cmd = sc->curcmd; + + /* We arrive here after receiving CMDRDY for a MMC_STOP_TRANSMISSION + * command. Depending on the operation being stopped, we may have to do + * some unusual things to work around hardware bugs. + */ + + /* This is known to be true of at91rm9200 hardware; it may or may not + * apply to more recent chips: + * + * After stopping a multi-block write, the NOTBUSY bit in MCI_SR does + * not properly reflect the actual busy state of the card as signaled on + * the DAT0 line; it always claims the card is not-busy. If we believe + * that and let operations continue, following commands will fail with + * response timeouts (except of course MMC_SEND_STATUS -- it indicates + * the card is busy in the PRG state, which was the smoking gun that + * showed MCI_SR NOTBUSY was not tracking DAT0 correctly). + * + * The atmel docs are emphatic: "This flag [NOTBUSY] must be used only + * for Write Operations." I guess technically since we sent a stop it's + * not a write operation anymore. But then just what did they think it + * meant for the stop command to have "...an optional busy signal + * transmitted on the data line" according to the SD spec? + * + * I tried a variety of things to un-wedge the MCI and get the status + * register to reflect NOTBUSY correctly again, but the only thing that + * worked was a full device reset. It feels like an awfully big hammer, + * but doing a full reset after every multiblock write is still faster + * than doing single-block IO (by almost two orders of magnitude: + * 20KB/sec improves to about 1.8MB/sec best case). + * + * After doing the reset, wait for a NOTBUSY interrupt before continuing + * with the next operation. + */ + + if (sc->flags & CMD_MULTIWRITE) { + at91_mci_reset(sc); + WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_NOTBUSY); + return; + } + + /* This is known to be true of at91rm9200 hardware; it may or may not + * apply to more recent chips: + * + * After stopping a multi-block read, loop to read and discard any data + * that coasts in after we sent the stop command. The docs don't say + * anything about it, but empirical testing shows that 1-3 additional + * words of data get buffered up in some unmentioned internal fifo and + * if we don't read and discard them here they end up on the front of + * the next read DMA transfer we do. + */ + + if (sc->flags & CMD_MULTIREAD) { + uint32_t sr; + int count = 0; + do { + sr = RD4(sc, MCI_SR); + if (sr & MCI_SR_RXRDY) { + RD4(sc, MCI_RDR); + ++count; + } + } while (sr & MCI_SR_RXRDY); + at91_mci_reset(sc); +// if (count != 0) +// printf("Had to soak up %d words after read\n", count); + } + + cmd->error = MMC_ERR_NONE; + at91_mci_next_operation(sc); + +} + +static void +at91_mci_cmdrdy(struct at91_mci_softc *sc, uint32_t sr) +{ + struct mmc_command *cmd = sc->curcmd; + int i; + + if (cmd == NULL) + return; + + /* We get here at the end of EVERY command. We retrieve the command + * response (if any) then decide what to do next based on the command. + */ + + if (cmd->flags & MMC_RSP_PRESENT) { + for (i = 0; i < ((cmd->flags & MMC_RSP_136) ? 4 : 1); i++) { + cmd->resp[i] = RD4(sc, MCI_RSPR + i * 4); + if (mci_debug) + printf("RSPR[%d] = %x sr=%x\n", i, cmd->resp[i], sr); + } + } + + /* If this was a stop command, go handle the various special + * conditions (read: bugs) that have to be dealt with following a stop. + */ + + if (cmd->opcode == MMC_STOP_TRANSMISSION) { + at91_mci_stop_done(sc, sr); + return; + } + + /* If this command can continue to assert BUSY beyond the response then + * we need to wait for NOTBUSY before the command is really done. + * + * Note that this may not work properly on the at91rm9200. It certainly + * doesn't work for the STOP command that follows a multi-block write, + * so post-stop CMDRDY is handled separately; see the special handling + * in at91_mci_stop_done(). + * + * Beside STOP, there are other R1B-type commands that use the busy + * signal after CMDRDY: CMD7 (card select), CMD28-29 (write protect), + * CMD38 (erase). I haven't tested any of them, but I rather expect + * them all to have the same sort of problem with MCI_SR not actually + * reflecting the state of the DAT0-line busy indicator. So this code + * may need to grow some sort of special handling for them too. (This + * just in: CMD7 isn't a problem right now because dev/mmc.c incorrectly + * sets the response flags to R1 rather than R1B.) + */ + + if ((cmd->flags & MMC_RSP_BUSY)) { + WR4(sc, MCI_IER, MCI_SR_ERROR | MCI_SR_NOTBUSY); + return; + } + + /* If there is a data transfer with this command, then... + * - If it's a read, we need to wait for ENDRX. + * - If it's a write, now is the time to enable the PDC, and we need to + * wait for a BLKE that follows a TXBUFE, because if we're doing a + * split transfer we get a BLKE after the first half (when TPR/TCR get + * loaded from TNPR/TNCR). So first we wait for the TXBUFE, and the + * handling for that interrupt will then invoke the wait for the + * subsequent BLKE which indicates actual completion. + */ + + if (cmd->data) { + uint32_t ier; + if (cmd->data->flags & MMC_DATA_READ) { + ier = MCI_SR_ENDRX; + } else { + ier = MCI_SR_TXBUFE; + WR4(sc, PDC_PTCR, PDC_PTCR_TXTEN); + } + WR4(sc, MCI_IER, MCI_SR_ERROR | ier); + return; + } + + /* If we made it to here, we don't need to wait for anything more for + * the current command, move on to the next command (will complete the + * request if there is no next command). + */ + + cmd->error = MMC_ERR_NONE; + at91_mci_next_operation(sc); } static void at91_mci_intr(void *arg) { struct at91_mci_softc *sc = (struct at91_mci_softc*)arg; - uint32_t sr; - int i, done = 0; - struct mmc_command *cmd; + struct mmc_command *cmd = sc->curcmd; + uint32_t sr, isr; AT91_MCI_LOCK(sc); - sr = RD4(sc, MCI_SR) & RD4(sc, MCI_IMR); -// printf("i 0x%x\n", sr); - cmd = sc->curcmd; - if (sr & MCI_SR_ERROR) { - // Ignore CRC errors on CMD2 and ACMD47, per relevant standards - if ((sr & MCI_SR_RCRCE) && (cmd->opcode == MMC_SEND_OP_COND || - cmd->opcode == ACMD_SD_SEND_OP_COND)) - cmd->error = MMC_ERR_NONE; - else if (sr & (MCI_SR_RTOE | MCI_SR_DTOE)) + + sr = RD4(sc, MCI_SR); + isr = sr & RD4(sc, MCI_IMR); + + if (mci_debug) + printf("i 0x%x sr 0x%x\n", isr, sr); + + /* All interrupts are one-shot; disable it now. + * The next operation will re-enable whatever interrupts it wants. + */ + + WR4(sc, MCI_IDR, isr); + + if (isr & MCI_SR_ERROR) { + if (isr & (MCI_SR_RTOE | MCI_SR_DTOE)) cmd->error = MMC_ERR_TIMEOUT; - else if (sr & (MCI_SR_RCRCE | MCI_SR_DCRCE)) + else if (isr & (MCI_SR_RCRCE | MCI_SR_DCRCE)) cmd->error = MMC_ERR_BADCRC; - else if (sr & (MCI_SR_OVRE | MCI_SR_UNRE)) + else if (isr & (MCI_SR_OVRE | MCI_SR_UNRE)) cmd->error = MMC_ERR_FIFO; else cmd->error = MMC_ERR_FAILED; - done = 1; - if (sc->mapped && cmd->error) { - bus_dmamap_unload(sc->dmatag, sc->map); - sc->mapped--; + /* CMD8 is used to probe for SDHC cards, a standard SD card will + * get a response timeout; don't report it because it's a normal + * and expected condition. One might argue that all error + * reporting should be left to higher levels, but when they + * report at all it's always EIO, which isn't very helpful. + */ + if (cmd->opcode != 8) { + device_printf(sc->dev, + "IO error; status MCI_SR = 0x%x cmd opcode = %d%s\n", + sr, cmd->opcode, + (cmd->opcode != 12) ? "" : + (sc->flags & CMD_MULTIREAD) ? " after read" : " after write"); + at91_mci_reset(sc); } + at91_mci_next_operation(sc); } else { - if (sr & MCI_SR_TXBUFE) { + if (isr & MCI_SR_TXBUFE) { // printf("TXBUFE\n"); - at91_mci_xmit_done(sc); + /* We need to wait for a BLKE that follows TXBUFE + * (intermediate BLKEs might happen after ENDTXes if + * we're chaining multiple buffers). If BLKE is also + * asserted at the time we get TXBUFE, we can avoid + * another interrupt and process it right away, below. + */ + if (sr & MCI_SR_BLKE) + isr |= MCI_SR_BLKE; + else + WR4(sc, MCI_IER, MCI_SR_BLKE); } - if (sr & MCI_SR_RXBUFF) { + if (isr & MCI_SR_RXBUFF) { // printf("RXBUFF\n"); - WR4(sc, MCI_IDR, MCI_SR_RXBUFF); - WR4(sc, MCI_IER, MCI_SR_CMDRDY); } - if (sr & MCI_SR_ENDTX) { + if (isr & MCI_SR_ENDTX) { // printf("ENDTX\n"); } - if (sr & MCI_SR_ENDRX) { + if (isr & MCI_SR_ENDRX) { // printf("ENDRX\n"); - at91_mci_read_done(sc); + at91_mci_read_done(sc, sr); } - if (sr & MCI_SR_NOTBUSY) { + if (isr & MCI_SR_NOTBUSY) { // printf("NOTBUSY\n"); - WR4(sc, MCI_IDR, MCI_SR_NOTBUSY); - WR4(sc, MCI_IER, MCI_SR_CMDRDY); + at91_mci_notbusy(sc); } - if (sr & MCI_SR_DTIP) { + if (isr & MCI_SR_DTIP) { // printf("Data transfer in progress\n"); } - if (sr & MCI_SR_BLKE) { + if (isr & MCI_SR_BLKE) { // printf("Block transfer end\n"); + at91_mci_write_done(sc, sr); } - if (sr & MCI_SR_TXRDY) { + if (isr & MCI_SR_TXRDY) { // printf("Ready to transmit\n"); } - if (sr & MCI_SR_RXRDY) { + if (isr & MCI_SR_RXRDY) { // printf("Ready to receive\n"); } - if (sr & MCI_SR_CMDRDY) { + if (isr & MCI_SR_CMDRDY) { // printf("Command ready\n"); - done = 1; - cmd->error = MMC_ERR_NONE; - } - } - if (done) { - WR4(sc, MCI_IDR, 0xffffffff); - if (cmd != NULL && (cmd->flags & MMC_RSP_PRESENT)) { - for (i = 0; i < ((cmd->flags & MMC_RSP_136) ? 4 : 1); - i++) { - cmd->resp[i] = RD4(sc, MCI_RSPR + i * 4); -// printf("RSPR[%d] = %x\n", i, cmd->resp[i]); - } + at91_mci_cmdrdy(sc, sr); } - at91_mci_start(sc); } AT91_MCI_UNLOCK(sc); } @@ -703,7 +1247,7 @@ *(int *)result = sc->host.caps; break; case MMCBR_IVAR_MAX_DATA: - *(int *)result = 1; + *(int *)result = MAX_BLOCKS; break; } return (0); From owner-freebsd-arm@FreeBSD.ORG Thu Apr 21 17:11:21 2011 Return-Path: Delivered-To: freebsd-arm@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A37D31065675 for ; Thu, 21 Apr 2011 17:11:21 +0000 (UTC) (envelope-from damjan.marion@gmail.com) Received: from mail-ew0-f54.google.com (mail-ew0-f54.google.com [209.85.215.54]) by mx1.freebsd.org (Postfix) with ESMTP id 3288A8FC17 for ; Thu, 21 Apr 2011 17:11:20 +0000 (UTC) Received: by ewy1 with SMTP id 1so715632ewy.13 for ; Thu, 21 Apr 2011 10:11:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:from:content-type:content-transfer-encoding :subject:date:message-id:cc:to:mime-version:x-mailer; bh=cul6BnAYNM1R38eyc3nyAipJds/5M6LHPNX/evwnfhw=; b=Ojgf2N+mmvkMva8eBR6L/JlMsicaC2It6OtCMOWFCmm+YbymIDVB6IOwi+jxBSZvsu 9huB2ZW0r2DkRtRyqUEldAlsWL8yJKdsXIGSs5Nsq6ic8lsWIIxRLOE/Cbz1F1mFWbMD B4BAHE+HeGQWdhx0v8R4ONX29MmL+SmIWXl40= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:content-type:content-transfer-encoding:subject:date:message-id :cc:to:mime-version:x-mailer; b=Jwged3blO2Fx3NS8WC7fKuLuZuB63d7Yp5RvkbZ/FgF2jb9GkoDYqY3oUU+2PBLET3 ksJl3uaKS0YyuzHUe50ic8BJT36qzk2A+TEVbgp9N7vLPWh0R0+eIWuOmzTjNKwt9ZY2 zfkFFGYclPEUuPNSLyX/IX4OJ/DWJMt1uSU9s= Received: by 10.213.28.144 with SMTP id m16mr779365ebc.119.1303405879661; Thu, 21 Apr 2011 10:11:19 -0700 (PDT) Received: from [192.168.123.4] (cpe-109-60-66-194.zg3.cable.xnet.hr [109.60.66.194]) by mx.google.com with ESMTPS id y7sm1480957eeh.0.2011.04.21.10.11.18 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 21 Apr 2011 10:11:18 -0700 (PDT) From: Damjan Marion Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Date: Thu, 21 Apr 2011 19:11:16 +0200 Message-Id: <77B4B008-D5A6-48A7-BAF9-E5084BF098DA@gmail.com> To: freebsd-toolchain@freebsd.org, freebsd-arm@freebsd.org Mime-Version: 1.0 (Apple Message framework v1084) X-Mailer: Apple Mail (2.1084) Cc: Subject: kernel cross-compiled with clang for ARM architecture X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Porting FreeBSD to the StrongARM Processor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Apr 2011 17:11:21 -0000 Hi, I managed to cross-compile latest -CURRENT + Ben's patches with clang = and compiled kernel boots on pandaboard. Pandaboard support is still work in progress, but clang compiled kernel = boots up to the same point like gcc version. I used latest clang/llvm from svn with following: CC=3D"/opt/llvm/bin/clang -mcpu=3Dcortex-a9 -ccc-host-triple = arm-unknown-freebsd -mfloat-abi=3Dsoft" WERROR=3D"" This works both on FreeBSD and Mac OS X host. Issues: - integrated assembler for ARM doesn't work properly ( I filled bugs = [1] and [2]) - gnu as works ok but newer version of binutils is needed which = supports ARMv7 instructions - i had to patch [3] clang to invoke cross linker properly (thanks to = guys form #freebsd-clang ) Regards, Damjan [1] http://llvm.org/bugs/show_bug.cgi?id=3D9760 [2] http://llvm.org/bugs/show_bug.cgi?id=3D9762 [3] http://llvm.org/bugs/show_bug.cgi?id=3D9777 From owner-freebsd-arm@FreeBSD.ORG Thu Apr 21 17:37:39 2011 Return-Path: Delivered-To: freebsd-arm@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id DE19D1065689 for ; Thu, 21 Apr 2011 17:37:39 +0000 (UTC) (envelope-from marktinguely@gmail.com) Received: from mail-iy0-f182.google.com (mail-iy0-f182.google.com [209.85.210.182]) by mx1.freebsd.org (Postfix) with ESMTP id 9E7C58FC15 for ; Thu, 21 Apr 2011 17:37:39 +0000 (UTC) Received: by iyj12 with SMTP id 12so2182067iyj.13 for ; Thu, 21 Apr 2011 10:37:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:message-id:date:from:user-agent:mime-version:to :cc:subject:references:in-reply-to:content-type :content-transfer-encoding; bh=ID6u2xh/QuC6iD4U4wsZ6aiV73YBxfQ8pTiHzcpVIPI=; b=gISVBMGE+Bzjlld4vUK8WksvpOii3fEfhiBMAusOrO30sR0cqfSyvwTAYSnMjD2+vG nPMymBPiDGjKpvY0/NXcLAClRs4PYXm+gXSHHo6Tq3h9KQTlZ8jcwqp2bj899c1lEbNO S7AA//MJjeHEStKY3yQQW6iFSHqpq8B4gQmPg= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type:content-transfer-encoding; b=pb36L/m9Ijq3ay5o61F/NdA4esX+g4iN6KWh8L5sNZW86OhOlCvx7PKenCPX85X/kq Vu03uyvlsXtbinYBWpz//XPo1U3yLR1/qwdjTc3f8HV0YTBYFpFmGqLZcPGz7fGwOmKo WabBO35DpRGi459wSqGF3d6F8XMprRur2L4Bo= Received: by 10.231.66.146 with SMTP id n18mr195063ibi.14.1303407459021; Thu, 21 Apr 2011 10:37:39 -0700 (PDT) Received: from [192.168.1.100] (c-24-245-26-12.hsd1.mn.comcast.net [24.245.26.12]) by mx.google.com with ESMTPS id g16sm833449ibb.37.2011.04.21.10.37.37 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 21 Apr 2011 10:37:38 -0700 (PDT) Message-ID: <4DB06B5E.3050707@gmail.com> Date: Thu, 21 Apr 2011 12:37:34 -0500 From: Mark Tinguely User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.15) Gecko/20110303 Thunderbird/3.1.9 MIME-Version: 1.0 To: Damjan Marion References: <77B4B008-D5A6-48A7-BAF9-E5084BF098DA@gmail.com> In-Reply-To: <77B4B008-D5A6-48A7-BAF9-E5084BF098DA@gmail.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: freebsd-arm@freebsd.org, freebsd-toolchain@freebsd.org Subject: Re: kernel cross-compiled with clang for ARM architecture X-BeenThere: freebsd-arm@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Porting FreeBSD to the StrongARM Processor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Apr 2011 17:37:39 -0000 On 4/21/2011 12:11 PM, Damjan Marion wrote: > Hi, > > I managed to cross-compile latest -CURRENT + Ben's patches with clang and compiled kernel boots on pandaboard. > Pandaboard support is still work in progress, but clang compiled kernel boots up to the same point like gcc version. > > I used latest clang/llvm from svn with following: > > CC="/opt/llvm/bin/clang -mcpu=cortex-a9 -ccc-host-triple arm-unknown-freebsd -mfloat-abi=soft" > WERROR="" > > This works both on FreeBSD and Mac OS X host. > > Issues: > - integrated assembler for ARM doesn't work properly ( I filled bugs [1] and [2]) > - gnu as works ok but newer version of binutils is needed which supports ARMv7 instructions > - i had to patch [3] clang to invoke cross linker properly (thanks to guys form #freebsd-clang ) > > > Regards, > > Damjan > > [1] http://llvm.org/bugs/show_bug.cgi?id=9760 > [2] http://llvm.org/bugs/show_bug.cgi?id=9762 > [3] http://llvm.org/bugs/show_bug.cgi?id=9777 > > _______________________________________________ > freebsd-arm@freebsd.org mailing list > http://lists.freebsd.org/mailman/listinfo/freebsd-arm > To unsubscribe, send any mail to "freebsd-arm-unsubscribe@freebsd.org" > Good job. I made a binutils 2.19 tar file that drops right into the source tree. It has many of the v7 features. http://www.tinguelys.info/mark/freebsd/binutils2.19.tgz LLVM is suppose to have utilities as well, which should be the long term solution. --Mark Tinguely