[PATCH] Add qword read/write support.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Warren Turkal <turkal@xxxxxxxxxx>
---
 lib/access.c |   15 +++++++++++++++
 lib/pci.h    |    2 ++
 lib/sysdep.h |   18 ++++++++++++++++++
 lib/types.h  |   35 +++++++++++++++++++++++------------
 setpci.c     |   18 +++++++++++++++---
 setpci.man   |    8 +++++---
 6 files changed, 78 insertions(+), 18 deletions(-)

diff --git a/lib/access.c b/lib/access.c
index 691df39..b8addea 100644
--- a/lib/access.c
+++ b/lib/access.c
@@ -98,6 +98,14 @@ pci_read_long(struct pci_dev *d, int pos)
   return le32_to_cpu(buf);
 }
 
+u64
+pci_read_quad(struct pci_dev *d, int pos)
+{
+  u64 buf;
+  pci_read_data(d, &buf, pos, 8);
+  return le64_to_cpu(buf);
+}
+
 int
 pci_read_block(struct pci_dev *d, int pos, byte *buf, int len)
 {
@@ -141,6 +149,13 @@ pci_write_long(struct pci_dev *d, int pos, u32 data)
 }
 
 int
+pci_write_quad(struct pci_dev *d, int pos, u64 data)
+{
+  u64 buf = cpu_to_le64(data);
+  return pci_write_data(d, &buf, pos, 8);
+}
+
+int
 pci_write_block(struct pci_dev *d, int pos, byte *buf, int len)
 {
   if (pos < d->cache_len)
diff --git a/lib/pci.h b/lib/pci.h
index 7a5a6b8..71d673f 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -147,11 +147,13 @@ struct pci_dev {
 u8 pci_read_byte(struct pci_dev *, int pos) PCI_ABI; /* Access to configuration space */
 u16 pci_read_word(struct pci_dev *, int pos) PCI_ABI;
 u32 pci_read_long(struct pci_dev *, int pos) PCI_ABI;
+u64 pci_read_quad(struct pci_dev *, int pos) PCI_ABI;
 int pci_read_block(struct pci_dev *, int pos, u8 *buf, int len) PCI_ABI;
 int pci_read_vpd(struct pci_dev *d, int pos, u8 *buf, int len) PCI_ABI;
 int pci_write_byte(struct pci_dev *, int pos, u8 data) PCI_ABI;
 int pci_write_word(struct pci_dev *, int pos, u16 data) PCI_ABI;
 int pci_write_long(struct pci_dev *, int pos, u32 data) PCI_ABI;
+int pci_write_quad(struct pci_dev *, int pos, u64 data) PCI_ABI;
 int pci_write_block(struct pci_dev *, int pos, u8 *buf, int len) PCI_ABI;
 
 int pci_fill_info(struct pci_dev *, int flags) PCI_ABI; /* Fill in device information */
diff --git a/lib/sysdep.h b/lib/sysdep.h
index 2a25c93..4701884 100644
--- a/lib/sysdep.h
+++ b/lib/sysdep.h
@@ -27,8 +27,10 @@ typedef u16 word;
 #include <asm/byteorder.h>
 #define cpu_to_le16 __cpu_to_le16
 #define cpu_to_le32 __cpu_to_le32
+#define cpu_to_le64 __cpu_to_le64
 #define le16_to_cpu __le16_to_cpu
 #define le32_to_cpu __le32_to_cpu
+#define le64_to_cpu __le64_to_cpu
 
 #else
 
@@ -63,8 +65,10 @@ typedef u16 word;
 #if BYTE_ORDER == BIG_ENDIAN
 #define cpu_to_le16 swab16
 #define cpu_to_le32 swab32
+#define cpu_to_le64 swab64
 #define le16_to_cpu swab16
 #define le32_to_cpu swab32
+#define le64_to_cpu swab64
 
 static inline word swab16(word w)
 {
@@ -78,11 +82,25 @@ static inline u32 swab32(u32 w)
          ((w & 0x0000ff00) << 8)  |
          ((w & 0x000000ff) << 24);
 }
+
+static inline u64 swab64(u64 w)
+{
+  return ((w & 0xff00000000000000) >> 56) |
+         ((w & 0x00ff000000000000) >> 40) |
+         ((w & 0x0000ff0000000000) >> 24) |
+         ((w & 0x000000ff00000000) >> 8) |
+         ((w & 0x00000000ff000000) << 8) |
+         ((w & 0x0000000000ff0000) << 24) |
+         ((w & 0x000000000000ff00) << 40) |
+         ((w & 0x00000000000000ff) << 56);
+}
 #else
 #define cpu_to_le16(x) (x)
 #define cpu_to_le32(x) (x)
+#define cpu_to_le64(x) (x)
 #define le16_to_cpu(x) (x)
 #define le32_to_cpu(x) (x)
+#define le64_to_cpu(x) (x)
 #endif
 
 #endif
diff --git a/lib/types.h b/lib/types.h
index 3e0e5c3..9bdd82a 100644
--- a/lib/types.h
+++ b/lib/types.h
@@ -15,39 +15,50 @@
 typedef BYTE u8;
 typedef WORD u16;
 typedef DWORD u32;
+typedef I64u u64;
+
+#ifdef PCI_HAVE_64BIT_ADDRESS
+#include <limits.h>
+#if ULONG_MAX > 0xffffffff
+#define PRIu64 "l"
+#else
+#define PRIu64 "ll"
+#endif
+#endif
+
 #elif defined(PCI_HAVE_STDINT_H) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
-#include <stdint.h>
+#include <inttypes.h>
 typedef uint8_t u8;
 typedef uint16_t u16;
 typedef uint32_t u32;
+typedef uint64_t u64;
 #else
+#include <inttypes.h>
 typedef u_int8_t u8;
 typedef u_int16_t u16;
 typedef u_int32_t u32;
+typedef u_int64_t u64;
 #endif
 
+#endif	/* PCI_HAVE_Uxx_TYPES */
+
 #ifdef PCI_HAVE_64BIT_ADDRESS
 #include <limits.h>
 #if ULONG_MAX > 0xffffffff
-typedef unsigned long u64;
-#define PCI_U64_FMT "l"
+typedef unsigned long pciaddr_t;
 #else
-typedef unsigned long long u64;
-#define PCI_U64_FMT "ll"
-#endif
+typedef unsigned long long pciaddr_t;
 #endif
 
-#endif	/* PCI_HAVE_Uxx_TYPES */
+#define PCIADDR_T_FMT "%08" PRIu64 "x"
+#define PCIADDR_PORT_FMT "%04" PRIu64 "x"
 
-#ifdef PCI_HAVE_64BIT_ADDRESS
-typedef u64 pciaddr_t;
-#define PCIADDR_T_FMT "%08" PCI_U64_FMT "x"
-#define PCIADDR_PORT_FMT "%04" PCI_U64_FMT "x"
 #else
 typedef u32 pciaddr_t;
 #define PCIADDR_T_FMT "%08x"
 #define PCIADDR_PORT_FMT "%04x"
-#endif
+
+#endif /* PCI_HAVE_64BIT_ADDRESS */
 
 #ifdef PCI_ARCH_SPARC64
 /* On sparc64 Linux the kernel reports remapped port addresses and IRQ numbers */
diff --git a/setpci.c b/setpci.c
index 97740e8..ebc89bc 100644
--- a/setpci.c
+++ b/setpci.c
@@ -73,9 +73,10 @@ trace(const char *fmt, ...)
 static void
 exec_op(struct op *op, struct pci_dev *dev)
 {
-  const char * const formats[] = { NULL, " %02x", " %04x", NULL, " %08x" };
-  const char * const mask_formats[] = { NULL, " %02x->(%02x:%02x)->%02x", " %04x->(%04x:%04x)->%04x", NULL, " %08x->(%08x:%08x)->%08x" };
-  unsigned int i, x, y;
+  const char * const formats[] = { NULL, " %02x", " %04x", NULL, " %08x", NULL, NULL, NULL, " %016" PRIu64 "x"};
+  const char * const mask_formats[] = { NULL, " %02x->(%02x:%02x)->%02x", " %04x->(%04x:%04x)->%04x", NULL, " %08x->(%08x:%08x)->%08x", NULL, NULL, NULL, " %016" PRIu64 "x->(%016" PRIu64 "x:%016" PRIu64 "x)->%016" PRIu64 "x"};
+  unsigned int i;
+  u64 x, y;
   int addr = 0;
   int width = op->width;
   char slot[16];
@@ -120,6 +121,9 @@ exec_op(struct op *op, struct pci_dev *dev)
 		case 2:
 		  y = pci_read_word(dev, addr);
 		  break;
+		case 8:
+		  y = pci_read_quad(dev, addr);
+		  break;
 		default:
 		  y = pci_read_long(dev, addr);
 		  break;
@@ -137,6 +141,9 @@ exec_op(struct op *op, struct pci_dev *dev)
 		case 2:
 		  pci_write_word(dev, addr, x);
 		  break;
+		case 8:
+		  pci_write_quad(dev, addr, x);
+		  break;
 		default:
 		  pci_write_long(dev, addr, x);
 		  break;
@@ -157,6 +164,9 @@ exec_op(struct op *op, struct pci_dev *dev)
 	case 2:
 	  x = pci_read_word(dev, addr);
 	  break;
+	case 8:
+	  x = pci_read_quad(dev, addr);
+	  break;
 	default:
 	  x = pci_read_long(dev, addr);
 	  break;
@@ -600,6 +610,8 @@ static void parse_op(char *c, struct pci_dev **selected_devices)
 	  op->width = 2; break;
 	case 'L':
 	  op->width = 4; break;
+	case 'Q':
+	  op->width = 8; break;
 	default:
 	  parse_err("Invalid width \"%c\"", *width);
 	}
diff --git a/setpci.man b/setpci.man
index 6c1ad8c..f4ba7d4 100644
--- a/setpci.man
+++ b/setpci.man
@@ -149,9 +149,11 @@ Each of the previous formats can be followed by \fB+offset\fP to add an offset
 (a hex number) to the address. This feature can be useful for addressing of registers
 living within a capability, or to modify parts of standard registers.
 \IP \(bu
-Finally, you should append a width specifier \fB.B\fP, \fB.W\fP, or \fB.L\fP to choose
-how many bytes (1, 2, or 4) should be transferred. The width can be omitted if you are
-accessing a named register whose width is well known.
+Finally, you should append a width specifier \fB.B\fP, \fB.W\fP, \fB.L\fP, or \fB.Q\fP
+to choose how many bytes (1, 2, 4, or 8) should be transferred. At the time of writing,
+8 byte wide read/writes are not atomic, and are executed as two 4 byte reads/writes.
+The width can be omitted if you are accessing a named register whose width is well
+known.
 
 .PP
 All names of registers and width specifiers are case-insensitive.
-- 
1.5.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux