Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 update from Martin Schwidefsky: "Add support to generate code for the latest machine zEC12, MOD and XOR instruction support for the BPF jit compiler, the dasd safe offline feature and the big one: the s390 architecture gets PCI support!! Right before the world ends on the 21st ;-)" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (41 commits) s390/qdio: rename the misleading PCI flag of qdio devices s390/pci: remove obsolete email addresses s390/pci: speed up __iowrite64_copy by using pci store block insn s390/pci: enable NEED_DMA_MAP_STATE s390/pci: no msleep in potential IRQ context s390/pci: fix potential NULL pointer dereference in dma_free_seg_table() s390/pci: use kmem_cache_zalloc instead of kmem_cache_alloc/memset s390/bpf,jit: add support for XOR instruction s390/bpf,jit: add support MOD instruction s390/cio: fix pgid reserved check vga: compile fix, disable vga for s390 s390/pci: add PCI Kconfig options s390/pci: s390 specific PCI sysfs attributes s390/pci: PCI hotplug support via SCLP s390/pci: CHSC PCI support for error and availability events s390/pci: DMA support s390/pci: PCI adapter interrupts for MSI/MSI-X s390/bitops: find leftmost bit instruction support s390/pci: CLP interface s390/pci: base support ...
This commit is contained in:
@@ -640,6 +640,87 @@ static inline unsigned long find_first_bit(const unsigned long * addr,
|
||||
}
|
||||
#define find_first_bit find_first_bit
|
||||
|
||||
/*
|
||||
* Big endian variant whichs starts bit counting from left using
|
||||
* the flogr (find leftmost one) instruction.
|
||||
*/
|
||||
static inline unsigned long __flo_word(unsigned long nr, unsigned long val)
|
||||
{
|
||||
register unsigned long bit asm("2") = val;
|
||||
register unsigned long out asm("3");
|
||||
|
||||
asm volatile (
|
||||
" .insn rre,0xb9830000,%[bit],%[bit]\n"
|
||||
: [bit] "+d" (bit), [out] "=d" (out) : : "cc");
|
||||
return nr + bit;
|
||||
}
|
||||
|
||||
/*
|
||||
* 64 bit special left bitops format:
|
||||
* order in memory:
|
||||
* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
|
||||
* 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
|
||||
* 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f
|
||||
* 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d 3e 3f
|
||||
* after that follows the next long with bit numbers
|
||||
* 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f
|
||||
* 50 51 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e 5f
|
||||
* 60 61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f
|
||||
* 70 71 72 73 74 75 76 77 78 79 7a 7b 7c 7d 7e 7f
|
||||
* The reason for this bit ordering is the fact that
|
||||
* the hardware sets bits in a bitmap starting at bit 0
|
||||
* and we don't want to scan the bitmap from the 'wrong
|
||||
* end'.
|
||||
*/
|
||||
static inline unsigned long find_first_bit_left(const unsigned long *addr,
|
||||
unsigned long size)
|
||||
{
|
||||
unsigned long bytes, bits;
|
||||
|
||||
if (!size)
|
||||
return 0;
|
||||
bytes = __ffs_word_loop(addr, size);
|
||||
bits = __flo_word(bytes * 8, __load_ulong_be(addr, bytes));
|
||||
return (bits < size) ? bits : size;
|
||||
}
|
||||
|
||||
static inline int find_next_bit_left(const unsigned long *addr,
|
||||
unsigned long size,
|
||||
unsigned long offset)
|
||||
{
|
||||
const unsigned long *p;
|
||||
unsigned long bit, set;
|
||||
|
||||
if (offset >= size)
|
||||
return size;
|
||||
bit = offset & (__BITOPS_WORDSIZE - 1);
|
||||
offset -= bit;
|
||||
size -= offset;
|
||||
p = addr + offset / __BITOPS_WORDSIZE;
|
||||
if (bit) {
|
||||
set = __flo_word(0, *p & (~0UL << bit));
|
||||
if (set >= size)
|
||||
return size + offset;
|
||||
if (set < __BITOPS_WORDSIZE)
|
||||
return set + offset;
|
||||
offset += __BITOPS_WORDSIZE;
|
||||
size -= __BITOPS_WORDSIZE;
|
||||
p++;
|
||||
}
|
||||
return offset + find_first_bit_left(p, size);
|
||||
}
|
||||
|
||||
#define for_each_set_bit_left(bit, addr, size) \
|
||||
for ((bit) = find_first_bit_left((addr), (size)); \
|
||||
(bit) < (size); \
|
||||
(bit) = find_next_bit_left((addr), (size), (bit) + 1))
|
||||
|
||||
/* same as for_each_set_bit() but use bit as value to start with */
|
||||
#define for_each_set_bit_left_cont(bit, addr, size) \
|
||||
for ((bit) = find_next_bit_left((addr), (size), (bit)); \
|
||||
(bit) < (size); \
|
||||
(bit) = find_next_bit_left((addr), (size), (bit) + 1))
|
||||
|
||||
/**
|
||||
* find_next_zero_bit - find the first zero bit in a memory region
|
||||
* @addr: The address to base the search on
|
||||
|
@@ -18,6 +18,9 @@ struct irb;
|
||||
struct ccw1;
|
||||
struct ccw_dev_id;
|
||||
|
||||
/* from asm/schid.h */
|
||||
struct subchannel_id;
|
||||
|
||||
/* simplified initializers for struct ccw_device:
|
||||
* CCW_DEVICE and CCW_DEVICE_DEVTYPE initialize one
|
||||
* entry in your MODULE_DEVICE_TABLE and set the match_flag correctly */
|
||||
@@ -223,8 +226,7 @@ extern int ccw_device_force_console(void);
|
||||
|
||||
int ccw_device_siosl(struct ccw_device *);
|
||||
|
||||
// FIXME: these have to go
|
||||
extern int _ccw_device_get_subchannel_number(struct ccw_device *);
|
||||
extern void ccw_device_get_schid(struct ccw_device *, struct subchannel_id *);
|
||||
|
||||
extern void *ccw_device_get_chp_desc(struct ccw_device *, int);
|
||||
#endif /* _S390_CCWDEV_H_ */
|
||||
|
@@ -59,6 +59,9 @@ extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver);
|
||||
int ccwgroup_create_dev(struct device *root, struct ccwgroup_driver *gdrv,
|
||||
int num_devices, const char *buf);
|
||||
|
||||
extern int ccwgroup_set_online(struct ccwgroup_device *gdev);
|
||||
extern int ccwgroup_set_offline(struct ccwgroup_device *gdev);
|
||||
|
||||
extern int ccwgroup_probe_ccwdev(struct ccw_device *cdev);
|
||||
extern void ccwgroup_remove_ccwdev(struct ccw_device *cdev);
|
||||
|
||||
|
28
arch/s390/include/asm/clp.h
Normal file
28
arch/s390/include/asm/clp.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef _ASM_S390_CLP_H
|
||||
#define _ASM_S390_CLP_H
|
||||
|
||||
/* CLP common request & response block size */
|
||||
#define CLP_BLK_SIZE (PAGE_SIZE * 2)
|
||||
|
||||
struct clp_req_hdr {
|
||||
u16 len;
|
||||
u16 cmd;
|
||||
} __packed;
|
||||
|
||||
struct clp_rsp_hdr {
|
||||
u16 len;
|
||||
u16 rsp;
|
||||
} __packed;
|
||||
|
||||
/* CLP Response Codes */
|
||||
#define CLP_RC_OK 0x0010 /* Command request successfully */
|
||||
#define CLP_RC_CMD 0x0020 /* Command code not recognized */
|
||||
#define CLP_RC_PERM 0x0030 /* Command not authorized */
|
||||
#define CLP_RC_FMT 0x0040 /* Invalid command request format */
|
||||
#define CLP_RC_LEN 0x0050 /* Invalid command request length */
|
||||
#define CLP_RC_8K 0x0060 /* Command requires 8K LPCB */
|
||||
#define CLP_RC_RESNOT0 0x0070 /* Reserved field not zero */
|
||||
#define CLP_RC_NODATA 0x0080 /* No data available */
|
||||
#define CLP_RC_FC_UNKNOWN 0x0100 /* Function code not recognized */
|
||||
|
||||
#endif
|
76
arch/s390/include/asm/dma-mapping.h
Normal file
76
arch/s390/include/asm/dma-mapping.h
Normal file
@@ -0,0 +1,76 @@
|
||||
#ifndef _ASM_S390_DMA_MAPPING_H
|
||||
#define _ASM_S390_DMA_MAPPING_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/dma-attrs.h>
|
||||
#include <linux/dma-debug.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#define DMA_ERROR_CODE (~(dma_addr_t) 0x0)
|
||||
|
||||
extern struct dma_map_ops s390_dma_ops;
|
||||
|
||||
static inline struct dma_map_ops *get_dma_ops(struct device *dev)
|
||||
{
|
||||
return &s390_dma_ops;
|
||||
}
|
||||
|
||||
extern int dma_set_mask(struct device *dev, u64 mask);
|
||||
extern int dma_is_consistent(struct device *dev, dma_addr_t dma_handle);
|
||||
extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
|
||||
enum dma_data_direction direction);
|
||||
|
||||
#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
|
||||
#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
|
||||
|
||||
#include <asm-generic/dma-mapping-common.h>
|
||||
|
||||
static inline int dma_supported(struct device *dev, u64 mask)
|
||||
{
|
||||
struct dma_map_ops *dma_ops = get_dma_ops(dev);
|
||||
|
||||
if (dma_ops->dma_supported == NULL)
|
||||
return 1;
|
||||
return dma_ops->dma_supported(dev, mask);
|
||||
}
|
||||
|
||||
static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
|
||||
{
|
||||
if (!dev->dma_mask)
|
||||
return 0;
|
||||
return addr + size - 1 <= *dev->dma_mask;
|
||||
}
|
||||
|
||||
static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
|
||||
{
|
||||
struct dma_map_ops *dma_ops = get_dma_ops(dev);
|
||||
|
||||
if (dma_ops->mapping_error)
|
||||
return dma_ops->mapping_error(dev, dma_addr);
|
||||
return (dma_addr == 0UL);
|
||||
}
|
||||
|
||||
static inline void *dma_alloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flag)
|
||||
{
|
||||
struct dma_map_ops *ops = get_dma_ops(dev);
|
||||
void *ret;
|
||||
|
||||
ret = ops->alloc(dev, size, dma_handle, flag, NULL);
|
||||
debug_dma_alloc_coherent(dev, size, *dma_handle, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void dma_free_coherent(struct device *dev, size_t size,
|
||||
void *cpu_addr, dma_addr_t dma_handle)
|
||||
{
|
||||
struct dma_map_ops *dma_ops = get_dma_ops(dev);
|
||||
|
||||
dma_ops->free(dev, size, cpu_addr, dma_handle, NULL);
|
||||
debug_dma_free_coherent(dev, size, cpu_addr, dma_handle);
|
||||
}
|
||||
|
||||
#endif /* _ASM_S390_DMA_MAPPING_H */
|
@@ -1,14 +1,13 @@
|
||||
#ifndef _ASM_S390_DMA_H
|
||||
#define _ASM_S390_DMA_H
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
/*
|
||||
* S390 version
|
||||
* MAX_DMA_ADDRESS is ambiguous because on s390 its completely unrelated
|
||||
* to DMA. It _is_ used for the s390 memory zone split at 2GB caused
|
||||
* by the 31 bit heritage.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_DMA_H
|
||||
#define _ASM_DMA_H
|
||||
|
||||
#include <asm/io.h> /* need byte IO */
|
||||
|
||||
#define MAX_DMA_ADDRESS 0x80000000
|
||||
|
||||
#define free_dma(x) do { } while (0)
|
||||
|
||||
#endif /* _ASM_DMA_H */
|
||||
#endif /* _ASM_S390_DMA_H */
|
||||
|
22
arch/s390/include/asm/hw_irq.h
Normal file
22
arch/s390/include/asm/hw_irq.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef _HW_IRQ_H
|
||||
#define _HW_IRQ_H
|
||||
|
||||
#include <linux/msi.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
static inline struct msi_desc *irq_get_msi_desc(unsigned int irq)
|
||||
{
|
||||
return __irq_get_msi_desc(irq);
|
||||
}
|
||||
|
||||
/* Must be called with msi map lock held */
|
||||
static inline int irq_set_msi_desc(unsigned int irq, struct msi_desc *msi)
|
||||
{
|
||||
if (!msi)
|
||||
return -EINVAL;
|
||||
|
||||
msi->irq = irq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
@@ -9,9 +9,9 @@
|
||||
#ifndef _S390_IO_H
|
||||
#define _S390_IO_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/page.h>
|
||||
|
||||
#define IO_SPACE_LIMIT 0xffffffff
|
||||
#include <asm/pci_io.h>
|
||||
|
||||
/*
|
||||
* Change virtual addresses to physical addresses and vv.
|
||||
@@ -24,10 +24,11 @@ static inline unsigned long virt_to_phys(volatile void * address)
|
||||
" lra %0,0(%1)\n"
|
||||
" jz 0f\n"
|
||||
" la %0,0\n"
|
||||
"0:"
|
||||
"0:"
|
||||
: "=a" (real_address) : "a" (address) : "cc");
|
||||
return real_address;
|
||||
return real_address;
|
||||
}
|
||||
#define virt_to_phys virt_to_phys
|
||||
|
||||
static inline void * phys_to_virt(unsigned long address)
|
||||
{
|
||||
@@ -42,4 +43,50 @@ void unxlate_dev_mem_ptr(unsigned long phys, void *addr);
|
||||
*/
|
||||
#define xlate_dev_kmem_ptr(p) p
|
||||
|
||||
#define IO_SPACE_LIMIT 0
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
#define ioremap_nocache(addr, size) ioremap(addr, size)
|
||||
#define ioremap_wc ioremap_nocache
|
||||
|
||||
/* TODO: s390 cannot support io_remap_pfn_range... */
|
||||
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
|
||||
remap_pfn_range(vma, vaddr, pfn, size, prot)
|
||||
|
||||
static inline void __iomem *ioremap(unsigned long offset, unsigned long size)
|
||||
{
|
||||
return (void __iomem *) offset;
|
||||
}
|
||||
|
||||
static inline void iounmap(volatile void __iomem *addr)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* s390 needs a private implementation of pci_iomap since ioremap with its
|
||||
* offset parameter isn't sufficient. That's because BAR spaces are not
|
||||
* disjunctive on s390 so we need the bar parameter of pci_iomap to find
|
||||
* the corresponding device and create the mapping cookie.
|
||||
*/
|
||||
#define pci_iomap pci_iomap
|
||||
#define pci_iounmap pci_iounmap
|
||||
|
||||
#define memcpy_fromio(dst, src, count) zpci_memcpy_fromio(dst, src, count)
|
||||
#define memcpy_toio(dst, src, count) zpci_memcpy_toio(dst, src, count)
|
||||
#define memset_io(dst, val, count) zpci_memset_io(dst, val, count)
|
||||
|
||||
#define __raw_readb zpci_read_u8
|
||||
#define __raw_readw zpci_read_u16
|
||||
#define __raw_readl zpci_read_u32
|
||||
#define __raw_readq zpci_read_u64
|
||||
#define __raw_writeb zpci_write_u8
|
||||
#define __raw_writew zpci_write_u16
|
||||
#define __raw_writel zpci_write_u32
|
||||
#define __raw_writeq zpci_write_u64
|
||||
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
#include <asm-generic/io.h>
|
||||
|
||||
#endif
|
||||
|
@@ -33,6 +33,8 @@ enum interruption_class {
|
||||
IOINT_APB,
|
||||
IOINT_ADM,
|
||||
IOINT_CSC,
|
||||
IOINT_PCI,
|
||||
IOINT_MSI,
|
||||
NMI_NMI,
|
||||
NR_IRQS,
|
||||
};
|
||||
@@ -51,4 +53,14 @@ void service_subclass_irq_unregister(void);
|
||||
void measurement_alert_subclass_register(void);
|
||||
void measurement_alert_subclass_unregister(void);
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
# define disable_irq_nosync_lockdep(irq) disable_irq_nosync(irq)
|
||||
# define disable_irq_nosync_lockdep_irqsave(irq, flags) \
|
||||
disable_irq_nosync(irq)
|
||||
# define disable_irq_lockdep(irq) disable_irq(irq)
|
||||
# define enable_irq_lockdep(irq) enable_irq(irq)
|
||||
# define enable_irq_lockdep_irqrestore(irq, flags) \
|
||||
enable_irq(irq)
|
||||
#endif
|
||||
|
||||
#endif /* _ASM_IRQ_H */
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#define CHSC_SCH_ISC 7 /* CHSC subchannels */
|
||||
/* Adapter interrupts. */
|
||||
#define QDIO_AIRQ_ISC IO_SCH_ISC /* I/O subchannel in qdio mode */
|
||||
#define PCI_ISC 2 /* PCI I/O subchannels */
|
||||
#define AP_ISC 6 /* adjunct processor (crypto) devices */
|
||||
|
||||
/* Functions for registration of I/O interruption subclasses */
|
||||
|
@@ -30,6 +30,8 @@
|
||||
#include <asm/setup.h>
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
void storage_key_init_range(unsigned long start, unsigned long end);
|
||||
|
||||
static unsigned long pfmf(unsigned long function, unsigned long address)
|
||||
{
|
||||
asm volatile(
|
||||
|
@@ -1,10 +1,158 @@
|
||||
#ifndef __ASM_S390_PCI_H
|
||||
#define __ASM_S390_PCI_H
|
||||
|
||||
/* S/390 systems don't have a PCI bus. This file is just here because some stupid .c code
|
||||
* includes it even if CONFIG_PCI is not set.
|
||||
*/
|
||||
/* must be set before including asm-generic/pci.h */
|
||||
#define PCI_DMA_BUS_IS_PHYS (0)
|
||||
/* must be set before including pci_clp.h */
|
||||
#define PCI_BAR_COUNT 6
|
||||
|
||||
#endif /* __ASM_S390_PCI_H */
|
||||
#include <asm-generic/pci.h>
|
||||
#include <asm-generic/pci-dma-compat.h>
|
||||
#include <asm/pci_clp.h>
|
||||
|
||||
#define PCIBIOS_MIN_IO 0x1000
|
||||
#define PCIBIOS_MIN_MEM 0x10000000
|
||||
|
||||
#define pcibios_assign_all_busses() (0)
|
||||
|
||||
void __iomem *pci_iomap(struct pci_dev *, int, unsigned long);
|
||||
void pci_iounmap(struct pci_dev *, void __iomem *);
|
||||
int pci_domain_nr(struct pci_bus *);
|
||||
int pci_proc_domain(struct pci_bus *);
|
||||
|
||||
/* MSI arch hooks */
|
||||
#define arch_setup_msi_irqs arch_setup_msi_irqs
|
||||
#define arch_teardown_msi_irqs arch_teardown_msi_irqs
|
||||
|
||||
#define ZPCI_BUS_NR 0 /* default bus number */
|
||||
#define ZPCI_DEVFN 0 /* default device number */
|
||||
|
||||
/* PCI Function Controls */
|
||||
#define ZPCI_FC_FN_ENABLED 0x80
|
||||
#define ZPCI_FC_ERROR 0x40
|
||||
#define ZPCI_FC_BLOCKED 0x20
|
||||
#define ZPCI_FC_DMA_ENABLED 0x10
|
||||
|
||||
struct msi_map {
|
||||
unsigned long irq;
|
||||
struct msi_desc *msi;
|
||||
struct hlist_node msi_chain;
|
||||
};
|
||||
|
||||
#define ZPCI_NR_MSI_VECS 64
|
||||
#define ZPCI_MSI_MASK (ZPCI_NR_MSI_VECS - 1)
|
||||
|
||||
enum zpci_state {
|
||||
ZPCI_FN_STATE_RESERVED,
|
||||
ZPCI_FN_STATE_STANDBY,
|
||||
ZPCI_FN_STATE_CONFIGURED,
|
||||
ZPCI_FN_STATE_ONLINE,
|
||||
NR_ZPCI_FN_STATES,
|
||||
};
|
||||
|
||||
struct zpci_bar_struct {
|
||||
u32 val; /* bar start & 3 flag bits */
|
||||
u8 size; /* order 2 exponent */
|
||||
u16 map_idx; /* index into bar mapping array */
|
||||
};
|
||||
|
||||
/* Private data per function */
|
||||
struct zpci_dev {
|
||||
struct pci_dev *pdev;
|
||||
struct pci_bus *bus;
|
||||
struct list_head entry; /* list of all zpci_devices, needed for hotplug, etc. */
|
||||
|
||||
enum zpci_state state;
|
||||
u32 fid; /* function ID, used by sclp */
|
||||
u32 fh; /* function handle, used by insn's */
|
||||
u16 pchid; /* physical channel ID */
|
||||
u8 pfgid; /* function group ID */
|
||||
u16 domain;
|
||||
|
||||
/* IRQ stuff */
|
||||
u64 msi_addr; /* MSI address */
|
||||
struct zdev_irq_map *irq_map;
|
||||
struct msi_map *msi_map[ZPCI_NR_MSI_VECS];
|
||||
unsigned int aisb; /* number of the summary bit */
|
||||
|
||||
/* DMA stuff */
|
||||
unsigned long *dma_table;
|
||||
spinlock_t dma_table_lock;
|
||||
int tlb_refresh;
|
||||
|
||||
spinlock_t iommu_bitmap_lock;
|
||||
unsigned long *iommu_bitmap;
|
||||
unsigned long iommu_size;
|
||||
unsigned long iommu_pages;
|
||||
unsigned int next_bit;
|
||||
|
||||
struct zpci_bar_struct bars[PCI_BAR_COUNT];
|
||||
|
||||
u64 start_dma; /* Start of available DMA addresses */
|
||||
u64 end_dma; /* End of available DMA addresses */
|
||||
u64 dma_mask; /* DMA address space mask */
|
||||
|
||||
enum pci_bus_speed max_bus_speed;
|
||||
};
|
||||
|
||||
struct pci_hp_callback_ops {
|
||||
int (*create_slot) (struct zpci_dev *zdev);
|
||||
void (*remove_slot) (struct zpci_dev *zdev);
|
||||
};
|
||||
|
||||
static inline bool zdev_enabled(struct zpci_dev *zdev)
|
||||
{
|
||||
return (zdev->fh & (1UL << 31)) ? true : false;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
Prototypes
|
||||
----------------------------------------------------------------------------- */
|
||||
/* Base stuff */
|
||||
struct zpci_dev *zpci_alloc_device(void);
|
||||
int zpci_create_device(struct zpci_dev *);
|
||||
int zpci_enable_device(struct zpci_dev *);
|
||||
void zpci_stop_device(struct zpci_dev *);
|
||||
void zpci_free_device(struct zpci_dev *);
|
||||
int zpci_scan_device(struct zpci_dev *);
|
||||
int zpci_register_ioat(struct zpci_dev *, u8, u64, u64, u64);
|
||||
int zpci_unregister_ioat(struct zpci_dev *, u8);
|
||||
|
||||
/* CLP */
|
||||
int clp_find_pci_devices(void);
|
||||
int clp_add_pci_device(u32, u32, int);
|
||||
int clp_enable_fh(struct zpci_dev *, u8);
|
||||
int clp_disable_fh(struct zpci_dev *);
|
||||
|
||||
/* MSI */
|
||||
struct msi_desc *__irq_get_msi_desc(unsigned int);
|
||||
int zpci_msi_set_mask_bits(struct msi_desc *, u32, u32);
|
||||
int zpci_setup_msi_irq(struct zpci_dev *, struct msi_desc *, unsigned int, int);
|
||||
void zpci_teardown_msi_irq(struct zpci_dev *, struct msi_desc *);
|
||||
int zpci_msihash_init(void);
|
||||
void zpci_msihash_exit(void);
|
||||
|
||||
/* Error handling and recovery */
|
||||
void zpci_event_error(void *);
|
||||
void zpci_event_availability(void *);
|
||||
|
||||
/* Helpers */
|
||||
struct zpci_dev *get_zdev(struct pci_dev *);
|
||||
struct zpci_dev *get_zdev_by_fid(u32);
|
||||
bool zpci_fid_present(u32);
|
||||
|
||||
/* sysfs */
|
||||
int zpci_sysfs_add_device(struct device *);
|
||||
void zpci_sysfs_remove_device(struct device *);
|
||||
|
||||
/* DMA */
|
||||
int zpci_dma_init(void);
|
||||
void zpci_dma_exit(void);
|
||||
|
||||
/* Hotplug */
|
||||
extern struct mutex zpci_list_lock;
|
||||
extern struct list_head zpci_list;
|
||||
extern struct pci_hp_callback_ops hotplug_ops;
|
||||
extern unsigned int pci_probe;
|
||||
|
||||
#endif
|
||||
|
182
arch/s390/include/asm/pci_clp.h
Normal file
182
arch/s390/include/asm/pci_clp.h
Normal file
@@ -0,0 +1,182 @@
|
||||
#ifndef _ASM_S390_PCI_CLP_H
|
||||
#define _ASM_S390_PCI_CLP_H
|
||||
|
||||
#include <asm/clp.h>
|
||||
|
||||
/*
|
||||
* Call Logical Processor - Command Codes
|
||||
*/
|
||||
#define CLP_LIST_PCI 0x0002
|
||||
#define CLP_QUERY_PCI_FN 0x0003
|
||||
#define CLP_QUERY_PCI_FNGRP 0x0004
|
||||
#define CLP_SET_PCI_FN 0x0005
|
||||
|
||||
/* PCI function handle list entry */
|
||||
struct clp_fh_list_entry {
|
||||
u16 device_id;
|
||||
u16 vendor_id;
|
||||
u32 config_state : 1;
|
||||
u32 : 31;
|
||||
u32 fid; /* PCI function id */
|
||||
u32 fh; /* PCI function handle */
|
||||
} __packed;
|
||||
|
||||
#define CLP_RC_SETPCIFN_FH 0x0101 /* Invalid PCI fn handle */
|
||||
#define CLP_RC_SETPCIFN_FHOP 0x0102 /* Fn handle not valid for op */
|
||||
#define CLP_RC_SETPCIFN_DMAAS 0x0103 /* Invalid DMA addr space */
|
||||
#define CLP_RC_SETPCIFN_RES 0x0104 /* Insufficient resources */
|
||||
#define CLP_RC_SETPCIFN_ALRDY 0x0105 /* Fn already in requested state */
|
||||
#define CLP_RC_SETPCIFN_ERR 0x0106 /* Fn in permanent error state */
|
||||
#define CLP_RC_SETPCIFN_RECPND 0x0107 /* Error recovery pending */
|
||||
#define CLP_RC_SETPCIFN_BUSY 0x0108 /* Fn busy */
|
||||
#define CLP_RC_LISTPCI_BADRT 0x010a /* Resume token not recognized */
|
||||
#define CLP_RC_QUERYPCIFG_PFGID 0x010b /* Unrecognized PFGID */
|
||||
|
||||
/* request or response block header length */
|
||||
#define LIST_PCI_HDR_LEN 32
|
||||
|
||||
/* Number of function handles fitting in response block */
|
||||
#define CLP_FH_LIST_NR_ENTRIES \
|
||||
((CLP_BLK_SIZE - 2 * LIST_PCI_HDR_LEN) \
|
||||
/ sizeof(struct clp_fh_list_entry))
|
||||
|
||||
#define CLP_SET_ENABLE_PCI_FN 0 /* Yes, 0 enables it */
|
||||
#define CLP_SET_DISABLE_PCI_FN 1 /* Yes, 1 disables it */
|
||||
|
||||
#define CLP_UTIL_STR_LEN 64
|
||||
|
||||
/* List PCI functions request */
|
||||
struct clp_req_list_pci {
|
||||
struct clp_req_hdr hdr;
|
||||
u32 fmt : 4; /* cmd request block format */
|
||||
u32 : 28;
|
||||
u64 reserved1;
|
||||
u64 resume_token;
|
||||
u64 reserved2;
|
||||
} __packed;
|
||||
|
||||
/* List PCI functions response */
|
||||
struct clp_rsp_list_pci {
|
||||
struct clp_rsp_hdr hdr;
|
||||
u32 fmt : 4; /* cmd request block format */
|
||||
u32 : 28;
|
||||
u64 reserved1;
|
||||
u64 resume_token;
|
||||
u32 reserved2;
|
||||
u16 max_fn;
|
||||
u8 reserved3;
|
||||
u8 entry_size;
|
||||
struct clp_fh_list_entry fh_list[CLP_FH_LIST_NR_ENTRIES];
|
||||
} __packed;
|
||||
|
||||
/* Query PCI function request */
|
||||
struct clp_req_query_pci {
|
||||
struct clp_req_hdr hdr;
|
||||
u32 fmt : 4; /* cmd request block format */
|
||||
u32 : 28;
|
||||
u64 reserved1;
|
||||
u32 fh; /* function handle */
|
||||
u32 reserved2;
|
||||
u64 reserved3;
|
||||
} __packed;
|
||||
|
||||
/* Query PCI function response */
|
||||
struct clp_rsp_query_pci {
|
||||
struct clp_rsp_hdr hdr;
|
||||
u32 fmt : 4; /* cmd request block format */
|
||||
u32 : 28;
|
||||
u64 reserved1;
|
||||
u16 vfn; /* virtual fn number */
|
||||
u16 : 7;
|
||||
u16 util_str_avail : 1; /* utility string available? */
|
||||
u16 pfgid : 8; /* pci function group id */
|
||||
u32 fid; /* pci function id */
|
||||
u8 bar_size[PCI_BAR_COUNT];
|
||||
u16 pchid;
|
||||
u32 bar[PCI_BAR_COUNT];
|
||||
u64 reserved2;
|
||||
u64 sdma; /* start dma as */
|
||||
u64 edma; /* end dma as */
|
||||
u64 reserved3[6];
|
||||
u8 util_str[CLP_UTIL_STR_LEN]; /* utility string */
|
||||
} __packed;
|
||||
|
||||
/* Query PCI function group request */
|
||||
struct clp_req_query_pci_grp {
|
||||
struct clp_req_hdr hdr;
|
||||
u32 fmt : 4; /* cmd request block format */
|
||||
u32 : 28;
|
||||
u64 reserved1;
|
||||
u32 : 24;
|
||||
u32 pfgid : 8; /* function group id */
|
||||
u32 reserved2;
|
||||
u64 reserved3;
|
||||
} __packed;
|
||||
|
||||
/* Query PCI function group response */
|
||||
struct clp_rsp_query_pci_grp {
|
||||
struct clp_rsp_hdr hdr;
|
||||
u32 fmt : 4; /* cmd request block format */
|
||||
u32 : 28;
|
||||
u64 reserved1;
|
||||
u16 : 4;
|
||||
u16 noi : 12; /* number of interrupts */
|
||||
u8 version;
|
||||
u8 : 6;
|
||||
u8 frame : 1;
|
||||
u8 refresh : 1; /* TLB refresh mode */
|
||||
u16 reserved2;
|
||||
u16 mui;
|
||||
u64 reserved3;
|
||||
u64 dasm; /* dma address space mask */
|
||||
u64 msia; /* MSI address */
|
||||
u64 reserved4;
|
||||
u64 reserved5;
|
||||
} __packed;
|
||||
|
||||
/* Set PCI function request */
|
||||
struct clp_req_set_pci {
|
||||
struct clp_req_hdr hdr;
|
||||
u32 fmt : 4; /* cmd request block format */
|
||||
u32 : 28;
|
||||
u64 reserved1;
|
||||
u32 fh; /* function handle */
|
||||
u16 reserved2;
|
||||
u8 oc; /* operation controls */
|
||||
u8 ndas; /* number of dma spaces */
|
||||
u64 reserved3;
|
||||
} __packed;
|
||||
|
||||
/* Set PCI function response */
|
||||
struct clp_rsp_set_pci {
|
||||
struct clp_rsp_hdr hdr;
|
||||
u32 fmt : 4; /* cmd request block format */
|
||||
u32 : 28;
|
||||
u64 reserved1;
|
||||
u32 fh; /* function handle */
|
||||
u32 reserved3;
|
||||
u64 reserved4;
|
||||
} __packed;
|
||||
|
||||
/* Combined request/response block structures used by clp insn */
|
||||
struct clp_req_rsp_list_pci {
|
||||
struct clp_req_list_pci request;
|
||||
struct clp_rsp_list_pci response;
|
||||
} __packed;
|
||||
|
||||
struct clp_req_rsp_set_pci {
|
||||
struct clp_req_set_pci request;
|
||||
struct clp_rsp_set_pci response;
|
||||
} __packed;
|
||||
|
||||
struct clp_req_rsp_query_pci {
|
||||
struct clp_req_query_pci request;
|
||||
struct clp_rsp_query_pci response;
|
||||
} __packed;
|
||||
|
||||
struct clp_req_rsp_query_pci_grp {
|
||||
struct clp_req_query_pci_grp request;
|
||||
struct clp_rsp_query_pci_grp response;
|
||||
} __packed;
|
||||
|
||||
#endif
|
196
arch/s390/include/asm/pci_dma.h
Normal file
196
arch/s390/include/asm/pci_dma.h
Normal file
@@ -0,0 +1,196 @@
|
||||
#ifndef _ASM_S390_PCI_DMA_H
|
||||
#define _ASM_S390_PCI_DMA_H
|
||||
|
||||
/* I/O Translation Anchor (IOTA) */
|
||||
enum zpci_ioat_dtype {
|
||||
ZPCI_IOTA_STO = 0,
|
||||
ZPCI_IOTA_RTTO = 1,
|
||||
ZPCI_IOTA_RSTO = 2,
|
||||
ZPCI_IOTA_RFTO = 3,
|
||||
ZPCI_IOTA_PFAA = 4,
|
||||
ZPCI_IOTA_IOPFAA = 5,
|
||||
ZPCI_IOTA_IOPTO = 7
|
||||
};
|
||||
|
||||
#define ZPCI_IOTA_IOT_ENABLED 0x800UL
|
||||
#define ZPCI_IOTA_DT_ST (ZPCI_IOTA_STO << 2)
|
||||
#define ZPCI_IOTA_DT_RT (ZPCI_IOTA_RTTO << 2)
|
||||
#define ZPCI_IOTA_DT_RS (ZPCI_IOTA_RSTO << 2)
|
||||
#define ZPCI_IOTA_DT_RF (ZPCI_IOTA_RFTO << 2)
|
||||
#define ZPCI_IOTA_DT_PF (ZPCI_IOTA_PFAA << 2)
|
||||
#define ZPCI_IOTA_FS_4K 0
|
||||
#define ZPCI_IOTA_FS_1M 1
|
||||
#define ZPCI_IOTA_FS_2G 2
|
||||
#define ZPCI_KEY (PAGE_DEFAULT_KEY << 5)
|
||||
|
||||
#define ZPCI_IOTA_STO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_ST)
|
||||
#define ZPCI_IOTA_RTTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RT)
|
||||
#define ZPCI_IOTA_RSTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RS)
|
||||
#define ZPCI_IOTA_RFTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RF)
|
||||
#define ZPCI_IOTA_RFAA_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_PF | ZPCI_IOTA_FS_2G)
|
||||
|
||||
/* I/O Region and segment tables */
|
||||
#define ZPCI_INDEX_MASK 0x7ffUL
|
||||
|
||||
#define ZPCI_TABLE_TYPE_MASK 0xc
|
||||
#define ZPCI_TABLE_TYPE_RFX 0xc
|
||||
#define ZPCI_TABLE_TYPE_RSX 0x8
|
||||
#define ZPCI_TABLE_TYPE_RTX 0x4
|
||||
#define ZPCI_TABLE_TYPE_SX 0x0
|
||||
|
||||
#define ZPCI_TABLE_LEN_RFX 0x3
|
||||
#define ZPCI_TABLE_LEN_RSX 0x3
|
||||
#define ZPCI_TABLE_LEN_RTX 0x3
|
||||
|
||||
#define ZPCI_TABLE_OFFSET_MASK 0xc0
|
||||
#define ZPCI_TABLE_SIZE 0x4000
|
||||
#define ZPCI_TABLE_ALIGN ZPCI_TABLE_SIZE
|
||||
#define ZPCI_TABLE_ENTRY_SIZE (sizeof(unsigned long))
|
||||
#define ZPCI_TABLE_ENTRIES (ZPCI_TABLE_SIZE / ZPCI_TABLE_ENTRY_SIZE)
|
||||
|
||||
#define ZPCI_TABLE_BITS 11
|
||||
#define ZPCI_PT_BITS 8
|
||||
#define ZPCI_ST_SHIFT (ZPCI_PT_BITS + PAGE_SHIFT)
|
||||
#define ZPCI_RT_SHIFT (ZPCI_ST_SHIFT + ZPCI_TABLE_BITS)
|
||||
|
||||
#define ZPCI_RTE_FLAG_MASK 0x3fffUL
|
||||
#define ZPCI_RTE_ADDR_MASK (~ZPCI_RTE_FLAG_MASK)
|
||||
#define ZPCI_STE_FLAG_MASK 0x7ffUL
|
||||
#define ZPCI_STE_ADDR_MASK (~ZPCI_STE_FLAG_MASK)
|
||||
|
||||
/* I/O Page tables */
|
||||
#define ZPCI_PTE_VALID_MASK 0x400
|
||||
#define ZPCI_PTE_INVALID 0x400
|
||||
#define ZPCI_PTE_VALID 0x000
|
||||
#define ZPCI_PT_SIZE 0x800
|
||||
#define ZPCI_PT_ALIGN ZPCI_PT_SIZE
|
||||
#define ZPCI_PT_ENTRIES (ZPCI_PT_SIZE / ZPCI_TABLE_ENTRY_SIZE)
|
||||
#define ZPCI_PT_MASK (ZPCI_PT_ENTRIES - 1)
|
||||
|
||||
#define ZPCI_PTE_FLAG_MASK 0xfffUL
|
||||
#define ZPCI_PTE_ADDR_MASK (~ZPCI_PTE_FLAG_MASK)
|
||||
|
||||
/* Shared bits */
|
||||
#define ZPCI_TABLE_VALID 0x00
|
||||
#define ZPCI_TABLE_INVALID 0x20
|
||||
#define ZPCI_TABLE_PROTECTED 0x200
|
||||
#define ZPCI_TABLE_UNPROTECTED 0x000
|
||||
|
||||
#define ZPCI_TABLE_VALID_MASK 0x20
|
||||
#define ZPCI_TABLE_PROT_MASK 0x200
|
||||
|
||||
static inline unsigned int calc_rtx(dma_addr_t ptr)
|
||||
{
|
||||
return ((unsigned long) ptr >> ZPCI_RT_SHIFT) & ZPCI_INDEX_MASK;
|
||||
}
|
||||
|
||||
static inline unsigned int calc_sx(dma_addr_t ptr)
|
||||
{
|
||||
return ((unsigned long) ptr >> ZPCI_ST_SHIFT) & ZPCI_INDEX_MASK;
|
||||
}
|
||||
|
||||
static inline unsigned int calc_px(dma_addr_t ptr)
|
||||
{
|
||||
return ((unsigned long) ptr >> PAGE_SHIFT) & ZPCI_PT_MASK;
|
||||
}
|
||||
|
||||
static inline void set_pt_pfaa(unsigned long *entry, void *pfaa)
|
||||
{
|
||||
*entry &= ZPCI_PTE_FLAG_MASK;
|
||||
*entry |= ((unsigned long) pfaa & ZPCI_PTE_ADDR_MASK);
|
||||
}
|
||||
|
||||
static inline void set_rt_sto(unsigned long *entry, void *sto)
|
||||
{
|
||||
*entry &= ZPCI_RTE_FLAG_MASK;
|
||||
*entry |= ((unsigned long) sto & ZPCI_RTE_ADDR_MASK);
|
||||
*entry |= ZPCI_TABLE_TYPE_RTX;
|
||||
}
|
||||
|
||||
static inline void set_st_pto(unsigned long *entry, void *pto)
|
||||
{
|
||||
*entry &= ZPCI_STE_FLAG_MASK;
|
||||
*entry |= ((unsigned long) pto & ZPCI_STE_ADDR_MASK);
|
||||
*entry |= ZPCI_TABLE_TYPE_SX;
|
||||
}
|
||||
|
||||
static inline void validate_rt_entry(unsigned long *entry)
|
||||
{
|
||||
*entry &= ~ZPCI_TABLE_VALID_MASK;
|
||||
*entry &= ~ZPCI_TABLE_OFFSET_MASK;
|
||||
*entry |= ZPCI_TABLE_VALID;
|
||||
*entry |= ZPCI_TABLE_LEN_RTX;
|
||||
}
|
||||
|
||||
static inline void validate_st_entry(unsigned long *entry)
|
||||
{
|
||||
*entry &= ~ZPCI_TABLE_VALID_MASK;
|
||||
*entry |= ZPCI_TABLE_VALID;
|
||||
}
|
||||
|
||||
static inline void invalidate_table_entry(unsigned long *entry)
|
||||
{
|
||||
*entry &= ~ZPCI_TABLE_VALID_MASK;
|
||||
*entry |= ZPCI_TABLE_INVALID;
|
||||
}
|
||||
|
||||
static inline void invalidate_pt_entry(unsigned long *entry)
|
||||
{
|
||||
WARN_ON_ONCE((*entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_INVALID);
|
||||
*entry &= ~ZPCI_PTE_VALID_MASK;
|
||||
*entry |= ZPCI_PTE_INVALID;
|
||||
}
|
||||
|
||||
static inline void validate_pt_entry(unsigned long *entry)
|
||||
{
|
||||
WARN_ON_ONCE((*entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID);
|
||||
*entry &= ~ZPCI_PTE_VALID_MASK;
|
||||
*entry |= ZPCI_PTE_VALID;
|
||||
}
|
||||
|
||||
static inline void entry_set_protected(unsigned long *entry)
|
||||
{
|
||||
*entry &= ~ZPCI_TABLE_PROT_MASK;
|
||||
*entry |= ZPCI_TABLE_PROTECTED;
|
||||
}
|
||||
|
||||
static inline void entry_clr_protected(unsigned long *entry)
|
||||
{
|
||||
*entry &= ~ZPCI_TABLE_PROT_MASK;
|
||||
*entry |= ZPCI_TABLE_UNPROTECTED;
|
||||
}
|
||||
|
||||
static inline int reg_entry_isvalid(unsigned long entry)
|
||||
{
|
||||
return (entry & ZPCI_TABLE_VALID_MASK) == ZPCI_TABLE_VALID;
|
||||
}
|
||||
|
||||
static inline int pt_entry_isvalid(unsigned long entry)
|
||||
{
|
||||
return (entry & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID;
|
||||
}
|
||||
|
||||
static inline int entry_isprotected(unsigned long entry)
|
||||
{
|
||||
return (entry & ZPCI_TABLE_PROT_MASK) == ZPCI_TABLE_PROTECTED;
|
||||
}
|
||||
|
||||
static inline unsigned long *get_rt_sto(unsigned long entry)
|
||||
{
|
||||
return ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_RTX)
|
||||
? (unsigned long *) (entry & ZPCI_RTE_ADDR_MASK)
|
||||
: NULL;
|
||||
}
|
||||
|
||||
static inline unsigned long *get_st_pto(unsigned long entry)
|
||||
{
|
||||
return ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_SX)
|
||||
? (unsigned long *) (entry & ZPCI_STE_ADDR_MASK)
|
||||
: NULL;
|
||||
}
|
||||
|
||||
/* Prototypes */
|
||||
int zpci_dma_init_device(struct zpci_dev *);
|
||||
void zpci_dma_exit_device(struct zpci_dev *);
|
||||
|
||||
#endif
|
280
arch/s390/include/asm/pci_insn.h
Normal file
280
arch/s390/include/asm/pci_insn.h
Normal file
@@ -0,0 +1,280 @@
|
||||
#ifndef _ASM_S390_PCI_INSN_H
|
||||
#define _ASM_S390_PCI_INSN_H
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define ZPCI_INSN_BUSY_DELAY 1 /* 1 microsecond */
|
||||
|
||||
/* Load/Store status codes */
|
||||
#define ZPCI_PCI_ST_FUNC_NOT_ENABLED 4
|
||||
#define ZPCI_PCI_ST_FUNC_IN_ERR 8
|
||||
#define ZPCI_PCI_ST_BLOCKED 12
|
||||
#define ZPCI_PCI_ST_INSUF_RES 16
|
||||
#define ZPCI_PCI_ST_INVAL_AS 20
|
||||
#define ZPCI_PCI_ST_FUNC_ALREADY_ENABLED 24
|
||||
#define ZPCI_PCI_ST_DMA_AS_NOT_ENABLED 28
|
||||
#define ZPCI_PCI_ST_2ND_OP_IN_INV_AS 36
|
||||
#define ZPCI_PCI_ST_FUNC_NOT_AVAIL 40
|
||||
#define ZPCI_PCI_ST_ALREADY_IN_RQ_STATE 44
|
||||
|
||||
/* Load/Store return codes */
|
||||
#define ZPCI_PCI_LS_OK 0
|
||||
#define ZPCI_PCI_LS_ERR 1
|
||||
#define ZPCI_PCI_LS_BUSY 2
|
||||
#define ZPCI_PCI_LS_INVAL_HANDLE 3
|
||||
|
||||
/* Load/Store address space identifiers */
|
||||
#define ZPCI_PCIAS_MEMIO_0 0
|
||||
#define ZPCI_PCIAS_MEMIO_1 1
|
||||
#define ZPCI_PCIAS_MEMIO_2 2
|
||||
#define ZPCI_PCIAS_MEMIO_3 3
|
||||
#define ZPCI_PCIAS_MEMIO_4 4
|
||||
#define ZPCI_PCIAS_MEMIO_5 5
|
||||
#define ZPCI_PCIAS_CFGSPC 15
|
||||
|
||||
/* Modify PCI Function Controls */
|
||||
#define ZPCI_MOD_FC_REG_INT 2
|
||||
#define ZPCI_MOD_FC_DEREG_INT 3
|
||||
#define ZPCI_MOD_FC_REG_IOAT 4
|
||||
#define ZPCI_MOD_FC_DEREG_IOAT 5
|
||||
#define ZPCI_MOD_FC_REREG_IOAT 6
|
||||
#define ZPCI_MOD_FC_RESET_ERROR 7
|
||||
#define ZPCI_MOD_FC_RESET_BLOCK 9
|
||||
#define ZPCI_MOD_FC_SET_MEASURE 10
|
||||
|
||||
/* FIB function controls */
|
||||
#define ZPCI_FIB_FC_ENABLED 0x80
|
||||
#define ZPCI_FIB_FC_ERROR 0x40
|
||||
#define ZPCI_FIB_FC_LS_BLOCKED 0x20
|
||||
#define ZPCI_FIB_FC_DMAAS_REG 0x10
|
||||
|
||||
/* FIB function controls */
|
||||
#define ZPCI_FIB_FC_ENABLED 0x80
|
||||
#define ZPCI_FIB_FC_ERROR 0x40
|
||||
#define ZPCI_FIB_FC_LS_BLOCKED 0x20
|
||||
#define ZPCI_FIB_FC_DMAAS_REG 0x10
|
||||
|
||||
/* Function Information Block */
|
||||
struct zpci_fib {
|
||||
u32 fmt : 8; /* format */
|
||||
u32 : 24;
|
||||
u32 reserved1;
|
||||
u8 fc; /* function controls */
|
||||
u8 reserved2;
|
||||
u16 reserved3;
|
||||
u32 reserved4;
|
||||
u64 pba; /* PCI base address */
|
||||
u64 pal; /* PCI address limit */
|
||||
u64 iota; /* I/O Translation Anchor */
|
||||
u32 : 1;
|
||||
u32 isc : 3; /* Interrupt subclass */
|
||||
u32 noi : 12; /* Number of interrupts */
|
||||
u32 : 2;
|
||||
u32 aibvo : 6; /* Adapter interrupt bit vector offset */
|
||||
u32 sum : 1; /* Adapter int summary bit enabled */
|
||||
u32 : 1;
|
||||
u32 aisbo : 6; /* Adapter int summary bit offset */
|
||||
u32 reserved5;
|
||||
u64 aibv; /* Adapter int bit vector address */
|
||||
u64 aisb; /* Adapter int summary bit address */
|
||||
u64 fmb_addr; /* Function measurement block address and key */
|
||||
u64 reserved6;
|
||||
u64 reserved7;
|
||||
} __packed;
|
||||
|
||||
/* Modify PCI Function Controls */
|
||||
static inline u8 __mpcifc(u64 req, struct zpci_fib *fib, u8 *status)
|
||||
{
|
||||
u8 cc;
|
||||
|
||||
asm volatile (
|
||||
" .insn rxy,0xe300000000d0,%[req],%[fib]\n"
|
||||
" ipm %[cc]\n"
|
||||
" srl %[cc],28\n"
|
||||
: [cc] "=d" (cc), [req] "+d" (req), [fib] "+Q" (*fib)
|
||||
: : "cc");
|
||||
*status = req >> 24 & 0xff;
|
||||
return cc;
|
||||
}
|
||||
|
||||
static inline int mpcifc_instr(u64 req, struct zpci_fib *fib)
|
||||
{
|
||||
u8 cc, status;
|
||||
|
||||
do {
|
||||
cc = __mpcifc(req, fib, &status);
|
||||
if (cc == 2)
|
||||
msleep(ZPCI_INSN_BUSY_DELAY);
|
||||
} while (cc == 2);
|
||||
|
||||
if (cc)
|
||||
printk_once(KERN_ERR "%s: error cc: %d status: %d\n",
|
||||
__func__, cc, status);
|
||||
return (cc) ? -EIO : 0;
|
||||
}
|
||||
|
||||
/* Refresh PCI Translations */
|
||||
static inline u8 __rpcit(u64 fn, u64 addr, u64 range, u8 *status)
|
||||
{
|
||||
register u64 __addr asm("2") = addr;
|
||||
register u64 __range asm("3") = range;
|
||||
u8 cc;
|
||||
|
||||
asm volatile (
|
||||
" .insn rre,0xb9d30000,%[fn],%[addr]\n"
|
||||
" ipm %[cc]\n"
|
||||
" srl %[cc],28\n"
|
||||
: [cc] "=d" (cc), [fn] "+d" (fn)
|
||||
: [addr] "d" (__addr), "d" (__range)
|
||||
: "cc");
|
||||
*status = fn >> 24 & 0xff;
|
||||
return cc;
|
||||
}
|
||||
|
||||
static inline int rpcit_instr(u64 fn, u64 addr, u64 range)
|
||||
{
|
||||
u8 cc, status;
|
||||
|
||||
do {
|
||||
cc = __rpcit(fn, addr, range, &status);
|
||||
if (cc == 2)
|
||||
udelay(ZPCI_INSN_BUSY_DELAY);
|
||||
} while (cc == 2);
|
||||
|
||||
if (cc)
|
||||
printk_once(KERN_ERR "%s: error cc: %d status: %d dma_addr: %Lx size: %Lx\n",
|
||||
__func__, cc, status, addr, range);
|
||||
return (cc) ? -EIO : 0;
|
||||
}
|
||||
|
||||
/* Store PCI function controls */
|
||||
static inline u8 __stpcifc(u32 handle, u8 space, struct zpci_fib *fib, u8 *status)
|
||||
{
|
||||
u64 fn = (u64) handle << 32 | space << 16;
|
||||
u8 cc;
|
||||
|
||||
asm volatile (
|
||||
" .insn rxy,0xe300000000d4,%[fn],%[fib]\n"
|
||||
" ipm %[cc]\n"
|
||||
" srl %[cc],28\n"
|
||||
: [cc] "=d" (cc), [fn] "+d" (fn), [fib] "=m" (*fib)
|
||||
: : "cc");
|
||||
*status = fn >> 24 & 0xff;
|
||||
return cc;
|
||||
}
|
||||
|
||||
/* Set Interruption Controls */
|
||||
static inline void sic_instr(u16 ctl, char *unused, u8 isc)
|
||||
{
|
||||
asm volatile (
|
||||
" .insn rsy,0xeb00000000d1,%[ctl],%[isc],%[u]\n"
|
||||
: : [ctl] "d" (ctl), [isc] "d" (isc << 27), [u] "Q" (*unused));
|
||||
}
|
||||
|
||||
/* PCI Load */
|
||||
static inline u8 __pcilg(u64 *data, u64 req, u64 offset, u8 *status)
|
||||
{
|
||||
register u64 __req asm("2") = req;
|
||||
register u64 __offset asm("3") = offset;
|
||||
u64 __data;
|
||||
u8 cc;
|
||||
|
||||
asm volatile (
|
||||
" .insn rre,0xb9d20000,%[data],%[req]\n"
|
||||
" ipm %[cc]\n"
|
||||
" srl %[cc],28\n"
|
||||
: [cc] "=d" (cc), [data] "=d" (__data), [req] "+d" (__req)
|
||||
: "d" (__offset)
|
||||
: "cc");
|
||||
*status = __req >> 24 & 0xff;
|
||||
*data = __data;
|
||||
return cc;
|
||||
}
|
||||
|
||||
static inline int pcilg_instr(u64 *data, u64 req, u64 offset)
|
||||
{
|
||||
u8 cc, status;
|
||||
|
||||
do {
|
||||
cc = __pcilg(data, req, offset, &status);
|
||||
if (cc == 2)
|
||||
udelay(ZPCI_INSN_BUSY_DELAY);
|
||||
} while (cc == 2);
|
||||
|
||||
if (cc) {
|
||||
printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n",
|
||||
__func__, cc, status, req, offset);
|
||||
/* TODO: on IO errors set data to 0xff...
|
||||
* here or in users of pcilg (le conversion)?
|
||||
*/
|
||||
}
|
||||
return (cc) ? -EIO : 0;
|
||||
}
|
||||
|
||||
/* PCI Store */
|
||||
static inline u8 __pcistg(u64 data, u64 req, u64 offset, u8 *status)
|
||||
{
|
||||
register u64 __req asm("2") = req;
|
||||
register u64 __offset asm("3") = offset;
|
||||
u8 cc;
|
||||
|
||||
asm volatile (
|
||||
" .insn rre,0xb9d00000,%[data],%[req]\n"
|
||||
" ipm %[cc]\n"
|
||||
" srl %[cc],28\n"
|
||||
: [cc] "=d" (cc), [req] "+d" (__req)
|
||||
: "d" (__offset), [data] "d" (data)
|
||||
: "cc");
|
||||
*status = __req >> 24 & 0xff;
|
||||
return cc;
|
||||
}
|
||||
|
||||
static inline int pcistg_instr(u64 data, u64 req, u64 offset)
|
||||
{
|
||||
u8 cc, status;
|
||||
|
||||
do {
|
||||
cc = __pcistg(data, req, offset, &status);
|
||||
if (cc == 2)
|
||||
udelay(ZPCI_INSN_BUSY_DELAY);
|
||||
} while (cc == 2);
|
||||
|
||||
if (cc)
|
||||
printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n",
|
||||
__func__, cc, status, req, offset);
|
||||
return (cc) ? -EIO : 0;
|
||||
}
|
||||
|
||||
/* PCI Store Block */
|
||||
static inline u8 __pcistb(const u64 *data, u64 req, u64 offset, u8 *status)
|
||||
{
|
||||
u8 cc;
|
||||
|
||||
asm volatile (
|
||||
" .insn rsy,0xeb00000000d0,%[req],%[offset],%[data]\n"
|
||||
" ipm %[cc]\n"
|
||||
" srl %[cc],28\n"
|
||||
: [cc] "=d" (cc), [req] "+d" (req)
|
||||
: [offset] "d" (offset), [data] "Q" (*data)
|
||||
: "cc");
|
||||
*status = req >> 24 & 0xff;
|
||||
return cc;
|
||||
}
|
||||
|
||||
static inline int pcistb_instr(const u64 *data, u64 req, u64 offset)
|
||||
{
|
||||
u8 cc, status;
|
||||
|
||||
do {
|
||||
cc = __pcistb(data, req, offset, &status);
|
||||
if (cc == 2)
|
||||
udelay(ZPCI_INSN_BUSY_DELAY);
|
||||
} while (cc == 2);
|
||||
|
||||
if (cc)
|
||||
printk_once(KERN_ERR "%s: error cc: %d status: %d req: %Lx offset: %Lx\n",
|
||||
__func__, cc, status, req, offset);
|
||||
return (cc) ? -EIO : 0;
|
||||
}
|
||||
|
||||
#endif
|
194
arch/s390/include/asm/pci_io.h
Normal file
194
arch/s390/include/asm/pci_io.h
Normal file
@@ -0,0 +1,194 @@
|
||||
#ifndef _ASM_S390_PCI_IO_H
|
||||
#define _ASM_S390_PCI_IO_H
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/pci_insn.h>
|
||||
|
||||
/* I/O Map */
|
||||
#define ZPCI_IOMAP_MAX_ENTRIES 0x7fff
|
||||
#define ZPCI_IOMAP_ADDR_BASE 0x8000000000000000ULL
|
||||
#define ZPCI_IOMAP_ADDR_IDX_MASK 0x7fff000000000000ULL
|
||||
#define ZPCI_IOMAP_ADDR_OFF_MASK 0x0000ffffffffffffULL
|
||||
|
||||
struct zpci_iomap_entry {
|
||||
u32 fh;
|
||||
u8 bar;
|
||||
};
|
||||
|
||||
extern struct zpci_iomap_entry *zpci_iomap_start;
|
||||
|
||||
#define ZPCI_IDX(addr) \
|
||||
(((__force u64) addr & ZPCI_IOMAP_ADDR_IDX_MASK) >> 48)
|
||||
#define ZPCI_OFFSET(addr) \
|
||||
((__force u64) addr & ZPCI_IOMAP_ADDR_OFF_MASK)
|
||||
|
||||
#define ZPCI_CREATE_REQ(handle, space, len) \
|
||||
((u64) handle << 32 | space << 16 | len)
|
||||
|
||||
#define zpci_read(LENGTH, RETTYPE) \
|
||||
static inline RETTYPE zpci_read_##RETTYPE(const volatile void __iomem *addr) \
|
||||
{ \
|
||||
struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)]; \
|
||||
u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH); \
|
||||
u64 data; \
|
||||
int rc; \
|
||||
\
|
||||
rc = pcilg_instr(&data, req, ZPCI_OFFSET(addr)); \
|
||||
if (rc) \
|
||||
data = -1ULL; \
|
||||
return (RETTYPE) data; \
|
||||
}
|
||||
|
||||
#define zpci_write(LENGTH, VALTYPE) \
|
||||
static inline void zpci_write_##VALTYPE(VALTYPE val, \
|
||||
const volatile void __iomem *addr) \
|
||||
{ \
|
||||
struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(addr)]; \
|
||||
u64 req = ZPCI_CREATE_REQ(entry->fh, entry->bar, LENGTH); \
|
||||
u64 data = (VALTYPE) val; \
|
||||
\
|
||||
pcistg_instr(data, req, ZPCI_OFFSET(addr)); \
|
||||
}
|
||||
|
||||
zpci_read(8, u64)
|
||||
zpci_read(4, u32)
|
||||
zpci_read(2, u16)
|
||||
zpci_read(1, u8)
|
||||
zpci_write(8, u64)
|
||||
zpci_write(4, u32)
|
||||
zpci_write(2, u16)
|
||||
zpci_write(1, u8)
|
||||
|
||||
static inline int zpci_write_single(u64 req, const u64 *data, u64 offset, u8 len)
|
||||
{
|
||||
u64 val;
|
||||
|
||||
switch (len) {
|
||||
case 1:
|
||||
val = (u64) *((u8 *) data);
|
||||
break;
|
||||
case 2:
|
||||
val = (u64) *((u16 *) data);
|
||||
break;
|
||||
case 4:
|
||||
val = (u64) *((u32 *) data);
|
||||
break;
|
||||
case 8:
|
||||
val = (u64) *((u64 *) data);
|
||||
break;
|
||||
default:
|
||||
val = 0; /* let FW report error */
|
||||
break;
|
||||
}
|
||||
return pcistg_instr(val, req, offset);
|
||||
}
|
||||
|
||||
static inline int zpci_read_single(u64 req, u64 *dst, u64 offset, u8 len)
|
||||
{
|
||||
u64 data;
|
||||
u8 cc;
|
||||
|
||||
cc = pcilg_instr(&data, req, offset);
|
||||
switch (len) {
|
||||
case 1:
|
||||
*((u8 *) dst) = (u8) data;
|
||||
break;
|
||||
case 2:
|
||||
*((u16 *) dst) = (u16) data;
|
||||
break;
|
||||
case 4:
|
||||
*((u32 *) dst) = (u32) data;
|
||||
break;
|
||||
case 8:
|
||||
*((u64 *) dst) = (u64) data;
|
||||
break;
|
||||
}
|
||||
return cc;
|
||||
}
|
||||
|
||||
static inline int zpci_write_block(u64 req, const u64 *data, u64 offset)
|
||||
{
|
||||
return pcistb_instr(data, req, offset);
|
||||
}
|
||||
|
||||
static inline u8 zpci_get_max_write_size(u64 src, u64 dst, int len, int max)
|
||||
{
|
||||
int count = len > max ? max : len, size = 1;
|
||||
|
||||
while (!(src & 0x1) && !(dst & 0x1) && ((size << 1) <= count)) {
|
||||
dst = dst >> 1;
|
||||
src = src >> 1;
|
||||
size = size << 1;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline int zpci_memcpy_fromio(void *dst,
|
||||
const volatile void __iomem *src,
|
||||
unsigned long n)
|
||||
{
|
||||
struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(src)];
|
||||
u64 req, offset = ZPCI_OFFSET(src);
|
||||
int size, rc = 0;
|
||||
|
||||
while (n > 0) {
|
||||
size = zpci_get_max_write_size((u64) src, (u64) dst, n, 8);
|
||||
req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size);
|
||||
rc = zpci_read_single(req, dst, offset, size);
|
||||
if (rc)
|
||||
break;
|
||||
offset += size;
|
||||
dst += size;
|
||||
n -= size;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int zpci_memcpy_toio(volatile void __iomem *dst,
|
||||
const void *src, unsigned long n)
|
||||
{
|
||||
struct zpci_iomap_entry *entry = &zpci_iomap_start[ZPCI_IDX(dst)];
|
||||
u64 req, offset = ZPCI_OFFSET(dst);
|
||||
int size, rc = 0;
|
||||
|
||||
if (!src)
|
||||
return -EINVAL;
|
||||
|
||||
while (n > 0) {
|
||||
size = zpci_get_max_write_size((u64) dst, (u64) src, n, 128);
|
||||
req = ZPCI_CREATE_REQ(entry->fh, entry->bar, size);
|
||||
|
||||
if (size > 8) /* main path */
|
||||
rc = zpci_write_block(req, src, offset);
|
||||
else
|
||||
rc = zpci_write_single(req, src, offset, size);
|
||||
if (rc)
|
||||
break;
|
||||
offset += size;
|
||||
src += size;
|
||||
n -= size;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline int zpci_memset_io(volatile void __iomem *dst,
|
||||
unsigned char val, size_t count)
|
||||
{
|
||||
u8 *src = kmalloc(count, GFP_KERNEL);
|
||||
int rc;
|
||||
|
||||
if (src == NULL)
|
||||
return -ENOMEM;
|
||||
memset(src, val, count);
|
||||
|
||||
rc = zpci_memcpy_toio(dst, src, count);
|
||||
kfree(src);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
#endif /* _ASM_S390_PCI_IO_H */
|
@@ -35,7 +35,6 @@
|
||||
extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
|
||||
extern void paging_init(void);
|
||||
extern void vmem_map_init(void);
|
||||
extern void fault_init(void);
|
||||
|
||||
/*
|
||||
* The S390 doesn't have any external MMU info: the kernel page
|
||||
@@ -336,6 +335,8 @@ extern unsigned long MODULES_END;
|
||||
#define _REGION3_ENTRY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_LENGTH)
|
||||
#define _REGION3_ENTRY_EMPTY (_REGION_ENTRY_TYPE_R3 | _REGION_ENTRY_INV)
|
||||
|
||||
#define _REGION3_ENTRY_LARGE 0x400 /* RTTE-format control, large page */
|
||||
|
||||
/* Bits in the segment table entry */
|
||||
#define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* segment table origin */
|
||||
#define _SEGMENT_ENTRY_RO 0x200 /* page protection bit */
|
||||
@@ -435,6 +436,7 @@ static inline int pgd_bad(pgd_t pgd) { return 0; }
|
||||
|
||||
static inline int pud_present(pud_t pud) { return 1; }
|
||||
static inline int pud_none(pud_t pud) { return 0; }
|
||||
static inline int pud_large(pud_t pud) { return 0; }
|
||||
static inline int pud_bad(pud_t pud) { return 0; }
|
||||
|
||||
#else /* CONFIG_64BIT */
|
||||
@@ -480,6 +482,13 @@ static inline int pud_none(pud_t pud)
|
||||
return (pud_val(pud) & _REGION_ENTRY_INV) != 0UL;
|
||||
}
|
||||
|
||||
static inline int pud_large(pud_t pud)
|
||||
{
|
||||
if ((pud_val(pud) & _REGION_ENTRY_TYPE_MASK) != _REGION_ENTRY_TYPE_R3)
|
||||
return 0;
|
||||
return !!(pud_val(pud) & _REGION3_ENTRY_LARGE);
|
||||
}
|
||||
|
||||
static inline int pud_bad(pud_t pud)
|
||||
{
|
||||
/*
|
||||
|
@@ -55,5 +55,7 @@ int sclp_chp_read_info(struct sclp_chp_info *info);
|
||||
void sclp_get_ipl_info(struct sclp_ipl_info *info);
|
||||
bool sclp_has_linemode(void);
|
||||
bool sclp_has_vt220(void);
|
||||
int sclp_pci_configure(u32 fid);
|
||||
int sclp_pci_deconfigure(u32 fid);
|
||||
|
||||
#endif /* _ASM_S390_SCLP_H */
|
||||
|
@@ -8,32 +8,34 @@ struct cpu;
|
||||
|
||||
#ifdef CONFIG_SCHED_BOOK
|
||||
|
||||
extern unsigned char cpu_socket_id[NR_CPUS];
|
||||
#define topology_physical_package_id(cpu) (cpu_socket_id[cpu])
|
||||
struct cpu_topology_s390 {
|
||||
unsigned short core_id;
|
||||
unsigned short socket_id;
|
||||
unsigned short book_id;
|
||||
cpumask_t core_mask;
|
||||
cpumask_t book_mask;
|
||||
};
|
||||
|
||||
extern unsigned char cpu_core_id[NR_CPUS];
|
||||
extern cpumask_t cpu_core_map[NR_CPUS];
|
||||
extern struct cpu_topology_s390 cpu_topology[NR_CPUS];
|
||||
|
||||
#define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id)
|
||||
#define topology_core_id(cpu) (cpu_topology[cpu].core_id)
|
||||
#define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_mask)
|
||||
#define topology_book_id(cpu) (cpu_topology[cpu].book_id)
|
||||
#define topology_book_cpumask(cpu) (&cpu_topology[cpu].book_mask)
|
||||
|
||||
#define mc_capable() 1
|
||||
|
||||
static inline const struct cpumask *cpu_coregroup_mask(int cpu)
|
||||
{
|
||||
return &cpu_core_map[cpu];
|
||||
return &cpu_topology[cpu].core_mask;
|
||||
}
|
||||
|
||||
#define topology_core_id(cpu) (cpu_core_id[cpu])
|
||||
#define topology_core_cpumask(cpu) (&cpu_core_map[cpu])
|
||||
#define mc_capable() (1)
|
||||
|
||||
extern unsigned char cpu_book_id[NR_CPUS];
|
||||
extern cpumask_t cpu_book_map[NR_CPUS];
|
||||
|
||||
static inline const struct cpumask *cpu_book_mask(int cpu)
|
||||
{
|
||||
return &cpu_book_map[cpu];
|
||||
return &cpu_topology[cpu].book_mask;
|
||||
}
|
||||
|
||||
#define topology_book_id(cpu) (cpu_book_id[cpu])
|
||||
#define topology_book_cpumask(cpu) (&cpu_book_map[cpu])
|
||||
|
||||
int topology_cpu_init(struct cpu *);
|
||||
int topology_set_cpu_management(int fc);
|
||||
void topology_schedule_update(void);
|
||||
|
6
arch/s390/include/asm/vga.h
Normal file
6
arch/s390/include/asm/vga.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef _ASM_S390_VGA_H
|
||||
#define _ASM_S390_VGA_H
|
||||
|
||||
/* Avoid compile errors due to missing asm/vga.h */
|
||||
|
||||
#endif /* _ASM_S390_VGA_H */
|
Reference in New Issue
Block a user