From patchwork Thu Jul 17 20:00:00 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guy Martin X-Patchwork-Id: 4578711 Return-Path: X-Original-To: patchwork-linux-parisc@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 4DE909F37C for ; Thu, 17 Jul 2014 20:12:06 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C598F20160 for ; Thu, 17 Jul 2014 20:12:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E1D7A2010F for ; Thu, 17 Jul 2014 20:12:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751436AbaGQUMC (ORCPT ); Thu, 17 Jul 2014 16:12:02 -0400 Received: from venus.vo.lu ([80.90.45.96]:54797 "EHLO venus.vo.lu" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751050AbaGQUMB (ORCPT ); Thu, 17 Jul 2014 16:12:01 -0400 X-Greylist: delayed 905 seconds by postgrey-1.27 at vger.kernel.org; Thu, 17 Jul 2014 16:12:00 EDT Received: from ibiza.lux.tuxicoman.be (UnknownHost [85.93.195.103]) by venus.vo.lu with SMTP (version=TLS\Tls cipher=Aes128 bits=128); Thu, 17 Jul 2014 21:56:09 +0200 Received: from [2001:7e8:2221:400:863a:4bff:fe82:d89c] (helo=dellete.lux.tuxicoman.be) by ibiza.lux.tuxicoman.be with esmtpsa (SSLv3:DHE-RSA-AES128-SHA:128) (Exim 4.80.1) (envelope-from ) id 1X7rnE-0000bP-JF for linux-parisc@vger.kernel.org; Thu, 17 Jul 2014 21:56:40 +0200 Date: Thu, 17 Jul 2014 22:00:00 +0200 From: Guy Martin To: linux-parisc Subject: [RFC PATCH] 64bit LWS CAS Message-ID: <20140717220000.555b2bec@dellete.lux.tuxicoman.be> X-Mailer: Claws Mail 3.9.0 (GTK+ 2.24.23; x86_64-pc-linux-gnu) Mime-Version: 1.0 Sender: linux-parisc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-parisc@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_TVD_MIME_EPI, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Hi, I've attached the gcc and kernel patch for 64bit CAS. So far I've implemented the easiest use case which is for 64bit kernel. I'll investigate using the FPU register for 64 bit operations with 32bit kernels. I feel like there is a lot of code duplication in my patches, this can probably be optimized altho it might reduce readability. Any comments ? Thanks, Guy --- libgcc/config/pa/linux-atomic.c.orig 2014-07-16 19:29:28.670595484 +0000 +++ libgcc/config/pa/linux-atomic.c 2014-07-16 19:31:32.754003341 +0000 @@ -24,6 +24,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ +#include + #define EFAULT 14 #define EBUSY 16 #define ENOSYS 251 @@ -75,6 +77,39 @@ return lws_errno; } +/* Kernel helper for compare-and-exchange a 64-bit value from ELF32. */ +static inline long +__kernel_cmpxchg_dword32 (int64_t oldval, int64_t newval, int64_t *mem) +{ + register unsigned long lws_mem asm("r26") = (unsigned long) (mem); + register long lws_ret_h asm("r28"); + register long lws_ret_l asm("r29"); + register long lws_errno asm("r21"); + register int lws_old_h asm("r25") = oldval >> 32; + register int lws_old_l asm("r24") = oldval & 0xffffffff; + register int lws_new_h asm("r23") = newval >> 32; + register int lws_new_l asm("r22") = newval & 0xffffffff; + asm volatile ( "ble 0xb0(%%sr2, %%r0) \n\t" + "ldi %8, %%r20 \n\t" + : "=r" (lws_ret_h), "=r" (lws_ret_l), "=r" (lws_errno), "=r" (lws_mem), + "=r" (lws_old_h), "=r" (lws_old_l), "=r" (lws_new_h), "=r" (lws_new_l) + : "i" (2), "3" (lws_mem), "4" (lws_old_h), "5" (lws_old_l), "6" (lws_new_h), "7" (lws_new_l) + : "r1", "r20", "r31", "memory" + ); + if (__builtin_expect (lws_errno == -EFAULT || lws_errno == -ENOSYS, 0)) + ABORT_INSTRUCTION; + + int64_t lws_ret = ((int64_t)lws_ret_h << 32) | (int64_t)lws_ret_l; + + /* If the kernel LWS call succeeded (lws_errno == 0), lws_ret contains + the old value from memory. If this value is equal to OLDVAL, the + new value was written to memory. If not, return -EBUSY. */ + if (!lws_errno && lws_ret != oldval) + lws_errno = -EBUSY; + + return lws_errno; +} + #define HIDDEN __attribute__ ((visibility ("hidden"))) /* Big endian masks */ @@ -84,6 +119,28 @@ #define MASK_1 0xffu #define MASK_2 0xffffu +#define FETCH_AND_OP_DWORD(OP, PFX_OP, INF_OP) \ + int64_t HIDDEN \ + __sync_fetch_and_##OP##_8 (int64_t *ptr, int64_t val) \ + { \ + int64_t tmp; \ + int failure; \ + \ + do { \ + tmp = *ptr; \ + failure = __kernel_cmpxchg_dword32 (tmp, PFX_OP (tmp INF_OP val), ptr); \ + } while (failure != 0); \ + \ + return tmp; \ + } + +FETCH_AND_OP_DWORD (add, , +) +FETCH_AND_OP_DWORD (sub, , -) +FETCH_AND_OP_DWORD (or, , |) +FETCH_AND_OP_DWORD (and, , &) +FETCH_AND_OP_DWORD (xor, , ^) +FETCH_AND_OP_DWORD (nand, ~, &) + #define FETCH_AND_OP_WORD(OP, PFX_OP, INF_OP) \ int HIDDEN \ __sync_fetch_and_##OP##_4 (int *ptr, int val) \ @@ -147,6 +204,28 @@ SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, oldval) SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, oldval) +#define OP_AND_FETCH_DWORD(OP, PFX_OP, INF_OP) \ + int64_t HIDDEN \ + __sync_##OP##_and_fetch_8 (int64_t *ptr, int64_t val) \ + { \ + int64_t tmp; \ + int failure; \ + \ + do { \ + tmp = *ptr; \ + failure = __kernel_cmpxchg_dword32 (tmp, PFX_OP (tmp INF_OP val), ptr); \ + } while (failure != 0); \ + \ + return PFX_OP (tmp INF_OP val); \ + } + +OP_AND_FETCH_DWORD (add, , +) +OP_AND_FETCH_DWORD (sub, , -) +OP_AND_FETCH_DWORD (or, , |) +OP_AND_FETCH_DWORD (and, , &) +OP_AND_FETCH_DWORD (xor, , ^) +OP_AND_FETCH_DWORD (nand, ~, &) + #define OP_AND_FETCH_WORD(OP, PFX_OP, INF_OP) \ int HIDDEN \ __sync_##OP##_and_fetch_4 (int *ptr, int val) \ @@ -182,6 +261,26 @@ SUBWORD_SYNC_OP (xor, , ^, unsigned char, 1, newval) SUBWORD_SYNC_OP (nand, ~, &, unsigned char, 1, newval) +int64_t HIDDEN +__sync_val_compare_and_swap_8 (int64_t *ptr, int64_t oldval, int64_t newval) +{ + int64_t actual_oldval; + int fail; + + while (1) + { + actual_oldval = *ptr; + + if (__builtin_expect (oldval != actual_oldval, 0)) + return actual_oldval; + + fail = __kernel_cmpxchg_dword32 (actual_oldval, newval, ptr); + + if (__builtin_expect (!fail, 1)) + return actual_oldval; + } +} + int HIDDEN __sync_val_compare_and_swap_4 (int *ptr, int oldval, int newval) { @@ -256,6 +355,20 @@ SUBWORD_BOOL_CAS (unsigned short, 2) SUBWORD_BOOL_CAS (unsigned char, 1) +int64_t HIDDEN +__sync_lock_test_and_set_8 (int64_t *ptr, int64_t val) +{ + int64_t oldval; + int failure; + + do { + oldval = *ptr; + failure = __kernel_cmpxchg_dword32 (oldval, val, ptr); + } while (failure != 0); + + return oldval; +} + int HIDDEN __sync_lock_test_and_set_4 (int *ptr, int val) { @@ -300,6 +413,7 @@ *ptr = 0; \ } -SYNC_LOCK_RELEASE (int, 4) -SYNC_LOCK_RELEASE (short, 2) -SYNC_LOCK_RELEASE (char, 1) +SYNC_LOCK_RELEASE (int64_t, 8) +SYNC_LOCK_RELEASE (int, 4) +SYNC_LOCK_RELEASE (short, 2) +SYNC_LOCK_RELEASE (char, 1)