Linux Audio

Check our new training course

Loading...
v6.2
  1/* SPDX-License-Identifier: GPL-2.0 */
  2#ifndef _ASM_S390_PCI_IO_H
  3#define _ASM_S390_PCI_IO_H
  4
  5#ifdef CONFIG_PCI
  6
  7#include <linux/kernel.h>
  8#include <linux/slab.h>
  9#include <asm/pci_insn.h>
 10
 11/* I/O size constraints */
 12#define ZPCI_MAX_READ_SIZE	8
 13#define ZPCI_MAX_WRITE_SIZE	128
 14
 15/* I/O Map */
 16#define ZPCI_IOMAP_SHIFT		48
 17#define ZPCI_IOMAP_ADDR_SHIFT		62
 18#define ZPCI_IOMAP_ADDR_BASE		(1UL << ZPCI_IOMAP_ADDR_SHIFT)
 19#define ZPCI_IOMAP_ADDR_OFF_MASK	((1UL << ZPCI_IOMAP_SHIFT) - 1)
 20#define ZPCI_IOMAP_MAX_ENTRIES							\
 21	(1UL << (ZPCI_IOMAP_ADDR_SHIFT - ZPCI_IOMAP_SHIFT))
 22#define ZPCI_IOMAP_ADDR_IDX_MASK						\
 23	((ZPCI_IOMAP_ADDR_BASE - 1) & ~ZPCI_IOMAP_ADDR_OFF_MASK)
 24
 25struct zpci_iomap_entry {
 26	u32 fh;
 27	u8 bar;
 28	u16 count;
 29};
 30
 31extern struct zpci_iomap_entry *zpci_iomap_start;
 32
 33#define ZPCI_ADDR(idx) (ZPCI_IOMAP_ADDR_BASE | ((u64) idx << ZPCI_IOMAP_SHIFT))
 34#define ZPCI_IDX(addr)								\
 35	(((__force u64) addr & ZPCI_IOMAP_ADDR_IDX_MASK) >> ZPCI_IOMAP_SHIFT)
 36#define ZPCI_OFFSET(addr)							\
 37	((__force u64) addr & ZPCI_IOMAP_ADDR_OFF_MASK)
 38
 39#define ZPCI_CREATE_REQ(handle, space, len)					\
 40	((u64) handle << 32 | space << 16 | len)
 41
 42#define zpci_read(LENGTH, RETTYPE)						\
 43static inline RETTYPE zpci_read_##RETTYPE(const volatile void __iomem *addr)	\
 44{										\
 
 
 45	u64 data;								\
 46	int rc;									\
 47										\
 48	rc = zpci_load(&data, addr, LENGTH);					\
 49	if (rc)									\
 50		data = -1ULL;							\
 51	return (RETTYPE) data;							\
 52}
 53
 54#define zpci_write(LENGTH, VALTYPE)						\
 55static inline void zpci_write_##VALTYPE(VALTYPE val,				\
 56					const volatile void __iomem *addr)	\
 57{										\
 
 
 58	u64 data = (VALTYPE) val;						\
 59										\
 60	zpci_store(addr, data, LENGTH);						\
 61}
 62
 63zpci_read(8, u64)
 64zpci_read(4, u32)
 65zpci_read(2, u16)
 66zpci_read(1, u8)
 67zpci_write(8, u64)
 68zpci_write(4, u32)
 69zpci_write(2, u16)
 70zpci_write(1, u8)
 71
 72static inline int zpci_write_single(volatile void __iomem *dst, const void *src,
 73				    unsigned long len)
 74{
 75	u64 val;
 76
 77	switch (len) {
 78	case 1:
 79		val = (u64) *((u8 *) src);
 80		break;
 81	case 2:
 82		val = (u64) *((u16 *) src);
 83		break;
 84	case 4:
 85		val = (u64) *((u32 *) src);
 86		break;
 87	case 8:
 88		val = (u64) *((u64 *) src);
 89		break;
 90	default:
 91		val = 0;		/* let FW report error */
 92		break;
 93	}
 94	return zpci_store(dst, val, len);
 95}
 96
 97static inline int zpci_read_single(void *dst, const volatile void __iomem *src,
 98				   unsigned long len)
 99{
100	u64 data;
101	int cc;
102
103	cc = zpci_load(&data, src, len);
104	if (cc)
105		goto out;
106
107	switch (len) {
108	case 1:
109		*((u8 *) dst) = (u8) data;
110		break;
111	case 2:
112		*((u16 *) dst) = (u16) data;
113		break;
114	case 4:
115		*((u32 *) dst) = (u32) data;
116		break;
117	case 8:
118		*((u64 *) dst) = (u64) data;
119		break;
120	}
121out:
122	return cc;
123}
124
125int zpci_write_block(volatile void __iomem *dst, const void *src,
126		     unsigned long len);
 
 
127
128static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max)
129{
130	int count = len > max ? max : len, size = 1;
131
132	while (!(src & 0x1) && !(dst & 0x1) && ((size << 1) <= count)) {
133		dst = dst >> 1;
134		src = src >> 1;
135		size = size << 1;
136	}
137	return size;
138}
139
140static inline int zpci_memcpy_fromio(void *dst,
141				     const volatile void __iomem *src,
142				     unsigned long n)
143{
 
 
144	int size, rc = 0;
145
146	while (n > 0) {
147		size = zpci_get_max_write_size((u64 __force) src,
148					       (u64) dst, n,
149					       ZPCI_MAX_READ_SIZE);
150		rc = zpci_read_single(dst, src, size);
151		if (rc)
152			break;
153		src += size;
154		dst += size;
155		n -= size;
156	}
157	return rc;
158}
159
160static inline int zpci_memcpy_toio(volatile void __iomem *dst,
161				   const void *src, unsigned long n)
162{
 
 
163	int size, rc = 0;
164
165	if (!src)
166		return -EINVAL;
167
168	while (n > 0) {
169		size = zpci_get_max_write_size((u64 __force) dst,
170					       (u64) src, n,
171					       ZPCI_MAX_WRITE_SIZE);
 
172		if (size > 8) /* main path */
173			rc = zpci_write_block(dst, src, size);
174		else
175			rc = zpci_write_single(dst, src, size);
176		if (rc)
177			break;
 
178		src += size;
179		dst += size;
180		n -= size;
181	}
182	return rc;
183}
184
185static inline int zpci_memset_io(volatile void __iomem *dst,
186				 unsigned char val, size_t count)
187{
188	u8 *src = kmalloc(count, GFP_KERNEL);
189	int rc;
190
191	if (src == NULL)
192		return -ENOMEM;
193	memset(src, val, count);
194
195	rc = zpci_memcpy_toio(dst, src, count);
196	kfree(src);
197	return rc;
198}
199
200#endif /* CONFIG_PCI */
201
202#endif /* _ASM_S390_PCI_IO_H */
v4.17
  1/* SPDX-License-Identifier: GPL-2.0 */
  2#ifndef _ASM_S390_PCI_IO_H
  3#define _ASM_S390_PCI_IO_H
  4
  5#ifdef CONFIG_PCI
  6
  7#include <linux/kernel.h>
  8#include <linux/slab.h>
  9#include <asm/pci_insn.h>
 10
 
 
 
 
 11/* I/O Map */
 12#define ZPCI_IOMAP_SHIFT		48
 13#define ZPCI_IOMAP_ADDR_BASE		0x8000000000000000UL
 
 14#define ZPCI_IOMAP_ADDR_OFF_MASK	((1UL << ZPCI_IOMAP_SHIFT) - 1)
 15#define ZPCI_IOMAP_MAX_ENTRIES							\
 16	((ULONG_MAX - ZPCI_IOMAP_ADDR_BASE + 1) / (1UL << ZPCI_IOMAP_SHIFT))
 17#define ZPCI_IOMAP_ADDR_IDX_MASK						\
 18	(~ZPCI_IOMAP_ADDR_OFF_MASK - ZPCI_IOMAP_ADDR_BASE)
 19
 20struct zpci_iomap_entry {
 21	u32 fh;
 22	u8 bar;
 23	u16 count;
 24};
 25
 26extern struct zpci_iomap_entry *zpci_iomap_start;
 27
 28#define ZPCI_ADDR(idx) (ZPCI_IOMAP_ADDR_BASE | ((u64) idx << ZPCI_IOMAP_SHIFT))
 29#define ZPCI_IDX(addr)								\
 30	(((__force u64) addr & ZPCI_IOMAP_ADDR_IDX_MASK) >> ZPCI_IOMAP_SHIFT)
 31#define ZPCI_OFFSET(addr)							\
 32	((__force u64) addr & ZPCI_IOMAP_ADDR_OFF_MASK)
 33
 34#define ZPCI_CREATE_REQ(handle, space, len)					\
 35	((u64) handle << 32 | space << 16 | len)
 36
 37#define zpci_read(LENGTH, RETTYPE)						\
 38static inline RETTYPE zpci_read_##RETTYPE(const volatile void __iomem *addr)	\
 39{										\
 40	struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];	\
 41	u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH);		\
 42	u64 data;								\
 43	int rc;									\
 44										\
 45	rc = zpci_load(&data, req, ZPCI_OFFSET(addr));				\
 46	if (rc)									\
 47		data = -1ULL;							\
 48	return (RETTYPE) data;							\
 49}
 50
 51#define zpci_write(LENGTH, VALTYPE)						\
 52static inline void zpci_write_##VALTYPE(VALTYPE val,				\
 53					const volatile void __iomem *addr)	\
 54{										\
 55	struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)];	\
 56	u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH);		\
 57	u64 data = (VALTYPE) val;						\
 58										\
 59	zpci_store(data, req, ZPCI_OFFSET(addr));				\
 60}
 61
 62zpci_read(8, u64)
 63zpci_read(4, u32)
 64zpci_read(2, u16)
 65zpci_read(1, u8)
 66zpci_write(8, u64)
 67zpci_write(4, u32)
 68zpci_write(2, u16)
 69zpci_write(1, u8)
 70
 71static inline int zpci_write_single(u64 req, const u64 *data, u64 offset, u8 len)
 
 72{
 73	u64 val;
 74
 75	switch (len) {
 76	case 1:
 77		val = (u64) *((u8 *) data);
 78		break;
 79	case 2:
 80		val = (u64) *((u16 *) data);
 81		break;
 82	case 4:
 83		val = (u64) *((u32 *) data);
 84		break;
 85	case 8:
 86		val = (u64) *((u64 *) data);
 87		break;
 88	default:
 89		val = 0;		/* let FW report error */
 90		break;
 91	}
 92	return zpci_store(val, req, offset);
 93}
 94
 95static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len)
 
 96{
 97	u64 data;
 98	int cc;
 99
100	cc = zpci_load(&data, req, offset);
101	if (cc)
102		goto out;
103
104	switch (len) {
105	case 1:
106		*((u8 *) dst) = (u8) data;
107		break;
108	case 2:
109		*((u16 *) dst) = (u16) data;
110		break;
111	case 4:
112		*((u32 *) dst) = (u32) data;
113		break;
114	case 8:
115		*((u64 *) dst) = (u64) data;
116		break;
117	}
118out:
119	return cc;
120}
121
122static inline int zpci_write_block(u64 req, const u64 *data, u64 offset)
123{
124	return zpci_store_block(data, req, offset);
125}
126
127static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max)
128{
129	int count = len > max ? max : len, size = 1;
130
131	while (!(src & 0x1) && !(dst & 0x1) && ((size << 1) <= count)) {
132		dst = dst >> 1;
133		src = src >> 1;
134		size = size << 1;
135	}
136	return size;
137}
138
139static inline int zpci_memcpy_fromio(void *dst,
140				     const volatile void __iomem *src,
141				     unsigned long n)
142{
143	struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(src)];
144	u64 req, offset = ZPCI_OFFSET(src);
145	int size, rc = 0;
146
147	while (n > 0) {
148		size = zpci_get_max_write_size((u64 __force) src,
149					       (u64) dst, n, 8);
150		req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size);
151		rc = zpci_read_single(req, dst, offset, size);
152		if (rc)
153			break;
154		offset += size;
155		dst += size;
156		n -= size;
157	}
158	return rc;
159}
160
161static inline int zpci_memcpy_toio(volatile void __iomem *dst,
162				   const void *src, unsigned long n)
163{
164	struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(dst)];
165	u64 req, offset = ZPCI_OFFSET(dst);
166	int size, rc = 0;
167
168	if (!src)
169		return -EINVAL;
170
171	while (n > 0) {
172		size = zpci_get_max_write_size((u64 __force) dst,
173					       (u64) src, n, 128);
174		req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size);
175
176		if (size > 8) /* main path */
177			rc = zpci_write_block(req, src, offset);
178		else
179			rc = zpci_write_single(req, src, offset, size);
180		if (rc)
181			break;
182		offset += size;
183		src += size;
 
184		n -= size;
185	}
186	return rc;
187}
188
189static inline int zpci_memset_io(volatile void __iomem *dst,
190				 unsigned char val, size_t count)
191{
192	u8 *src = kmalloc(count, GFP_KERNEL);
193	int rc;
194
195	if (src == NULL)
196		return -ENOMEM;
197	memset(src, val, count);
198
199	rc = zpci_memcpy_toio(dst, src, count);
200	kfree(src);
201	return rc;
202}
203
204#endif /* CONFIG_PCI */
205
206#endif /* _ASM_S390_PCI_IO_H */