Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6: (23 commits)
  [SPARC64]: virt_to_real_irq_table --> virt_irq_table
  [SPARC64]: virt_irq --> bucket mapping no longer necessary
  [SPARC64]: Kill ugly __bucket() macro.
  [SPARC64]: Kill ugly __irq_ino() macro.
  [SPARC64]: Only use bypass accesses to INO buckets.
  [SPARC64]: Update defconfig.
  [SPARC64]: Use sun4v VIRQ interfaces as intended.
  [SPARC64]: Allocate ivector_table dynamically.
  [SPARC64]: Access ivector_table[] using physical addresses.
  [SPARC64]: Make IVEC pointers 64-bit.
  [SPARC64]: Fix register usage in xor_raid_4().
  [SPARC64]: Kill pci_memspace_mask.
  [SPARC64]: Consolidate MSI support code.
  [SPARC/64]: Move of_platform_driver initialisations: arch/sparc{,64}.
  [SPARC64]: Fix bugs in SYSV IPC handling in 64-bit processes.
  [SPARC/64]: Prepare to remove of_platform_driver name.
  [SPARC32]: Add irqflags.h to sparc32 and use it from generic code.
  [SPARC64]: beautify vmlinux.lds
  [SPARC]: beautify vmlinux.lds
  [SPARC64]: Enable MSI on sun4u Fire PCI-E controllers.
  ...
This commit is contained in:
Linus Torvalds
2007-10-14 08:59:48 -07:00
33 changed files with 1767 additions and 1155 deletions
+3 -1
View File
@@ -67,10 +67,12 @@ probe in an SBUS driver under Linux:
MODULE_DEVICE_TABLE(of, mydevice_match);
static struct of_platform_driver mydevice_driver = {
.name = "mydevice",
.match_table = mydevice_match,
.probe = mydevice_probe,
.remove = __devexit_p(mydevice_remove),
.driver = {
.name = "mydevice",
},
};
static int __init mydevice_init(void)
+4
View File
@@ -1,5 +1,9 @@
menu "Kernel hacking"
config TRACE_IRQFLAGS_SUPPORT
bool
default y
source "lib/Kconfig.debug"
config DEBUG_STACK_USAGE
+6 -6
View File
@@ -56,7 +56,7 @@
#define SMP_NOP2
#define SMP_NOP3
#endif /* SMP */
unsigned long __local_irq_save(void)
unsigned long __raw_local_irq_save(void)
{
unsigned long retval;
unsigned long tmp;
@@ -74,7 +74,7 @@ unsigned long __local_irq_save(void)
return retval;
}
void local_irq_enable(void)
void raw_local_irq_enable(void)
{
unsigned long tmp;
@@ -89,7 +89,7 @@ void local_irq_enable(void)
: "memory");
}
void local_irq_restore(unsigned long old_psr)
void raw_local_irq_restore(unsigned long old_psr)
{
unsigned long tmp;
@@ -105,9 +105,9 @@ void local_irq_restore(unsigned long old_psr)
: "memory");
}
EXPORT_SYMBOL(__local_irq_save);
EXPORT_SYMBOL(local_irq_enable);
EXPORT_SYMBOL(local_irq_restore);
EXPORT_SYMBOL(__raw_local_irq_save);
EXPORT_SYMBOL(raw_local_irq_enable);
EXPORT_SYMBOL(raw_local_irq_restore);
/*
* Dave Redman (djhr@tadpole.co.uk)
+4 -1
View File
@@ -588,7 +588,10 @@ __setup("of_debug=", of_debug);
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
/* initialize common driver fields */
drv->driver.name = drv->name;
if (!drv->driver.name)
drv->driver.name = drv->name;
if (!drv->driver.owner)
drv->driver.owner = drv->owner;
drv->driver.bus = bus;
/* register with core */
+3 -1
View File
@@ -347,9 +347,11 @@ static struct of_device_id clock_match[] = {
};
static struct of_platform_driver clock_driver = {
.name = "clock",
.match_table = clock_match,
.probe = clock_probe,
.driver = {
.name = "clock",
},
};
+93 -72
View File
@@ -1,6 +1,7 @@
/* ld script to make SparcLinux kernel */
#include <asm-generic/vmlinux.lds.h>
#include <asm/page.h>
OUTPUT_FORMAT("elf32-sparc", "elf32-sparc", "elf32-sparc")
OUTPUT_ARCH(sparc)
@@ -8,84 +9,104 @@ ENTRY(_start)
jiffies = jiffies_64 + 4;
SECTIONS
{
. = 0x10000 + SIZEOF_HEADERS;
.text 0xf0004000 :
{
_text = .;
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
*(.gnu.warning)
} =0
_etext = .;
PROVIDE (etext = .);
RODATA
.data :
{
DATA_DATA
CONSTRUCTORS
}
.data1 : { *(.data1) }
_edata = .;
PROVIDE (edata = .);
__start___fixup = .;
.fixup : { *(.fixup) }
__stop___fixup = .;
__start___ex_table = .;
__ex_table : { *(__ex_table) }
__stop___ex_table = .;
. = 0x10000 + SIZEOF_HEADERS;
.text 0xf0004000 :
{
_text = .;
TEXT_TEXT
SCHED_TEXT
LOCK_TEXT
*(.gnu.warning)
} = 0
_etext = .;
PROVIDE (etext = .);
RODATA
.data : {
DATA_DATA
CONSTRUCTORS
}
.data1 : {
*(.data1)
}
_edata = .;
PROVIDE (edata = .);
NOTES
.fixup : {
__start___fixup = .;
*(.fixup)
__stop___fixup = .;
}
__ex_table : {
__start___ex_table = .;
*(__ex_table)
__stop___ex_table = .;
}
. = ALIGN(4096);
__init_begin = .;
_sinittext = .;
.init.text : {
*(.init.text)
}
_einittext = .;
__init_text_end = .;
.init.data : { *(.init.data) }
. = ALIGN(16);
__setup_start = .;
.init.setup : { *(.init.setup) }
__setup_end = .;
__initcall_start = .;
.initcall.init : {
INITCALLS
}
__initcall_end = .;
__con_initcall_start = .;
.con_initcall.init : { *(.con_initcall.init) }
__con_initcall_end = .;
SECURITY_INIT
NOTES
. = ALIGN(PAGE_SIZE);
__init_begin = .;
.init.text : {
_sinittext = .;
*(.init.text)
_einittext = .;
}
__init_text_end = .;
.init.data : {
*(.init.data)
}
. = ALIGN(16);
.init.setup : {
__setup_start = .;
*(.init.setup)
__setup_end = .;
}
.initcall.init : {
__initcall_start = .;
INITCALLS
__initcall_end = .;
}
.con_initcall.init : {
__con_initcall_start = .;
*(.con_initcall.init)
__con_initcall_end = .;
}
SECURITY_INIT
#ifdef CONFIG_BLK_DEV_INITRD
. = ALIGN(4096);
__initramfs_start = .;
.init.ramfs : { *(.init.ramfs) }
__initramfs_end = .;
. = ALIGN(PAGE_SIZE);
.init.ramfs : {
__initramfs_start = .;
*(.init.ramfs)
__initramfs_end = .;
}
#endif
PERCPU(4096)
. = ALIGN(4096);
__init_end = .;
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
PERCPU(PAGE_SIZE)
. = ALIGN(PAGE_SIZE);
__init_end = .;
. = ALIGN(32);
.data.cacheline_aligned : {
*(.data.cacheline_aligned)
}
__bss_start = .;
.sbss : { *(.sbss) *(.scommon) }
.bss :
{
*(.dynbss)
*(.bss)
*(COMMON)
}
_end = . ;
PROVIDE (end = .);
/DISCARD/ : { *(.exit.text) *(.exit.data) *(.exitcall.exit) }
__bss_start = .;
.sbss : {
*(.sbss)
*(.scommon) }
.bss : {
*(.dynbss)
*(.bss)
*(COMMON)
}
_end = . ;
PROVIDE (end = .);
/DISCARD/ : {
*(.exit.text)
*(.exit.data)
*(.exitcall.exit)
}
STABS_DEBUG
DWARF_DEBUG
STABS_DEBUG
DWARF_DEBUG
}
+33 -5
View File
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.23-rc6
# Sun Sep 16 09:52:11 2007
# Linux kernel version: 2.6.23
# Sat Oct 13 21:53:54 2007
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@@ -69,7 +69,6 @@ CONFIG_FUTEX=y
CONFIG_ANON_INODES=y
CONFIG_EPOLL=y
CONFIG_SIGNALFD=y
CONFIG_TIMERFD=y
CONFIG_EVENTFD=y
CONFIG_SHMEM=y
CONFIG_VM_EVENT_COUNTERS=y
@@ -89,6 +88,7 @@ CONFIG_KMOD=y
CONFIG_BLOCK=y
CONFIG_BLK_DEV_IO_TRACE=y
CONFIG_BLK_DEV_BSG=y
CONFIG_BLOCK_COMPAT=y
#
# IO Schedulers
@@ -111,6 +111,7 @@ CONFIG_GENERIC_HARDIRQS=y
CONFIG_TICK_ONESHOT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
# CONFIG_SMP is not set
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=m
@@ -119,6 +120,8 @@ CONFIG_CPU_FREQ_STAT=m
CONFIG_CPU_FREQ_STAT_DETAILS=y
CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=m
CONFIG_CPU_FREQ_GOV_USERSPACE=m
@@ -213,6 +216,7 @@ CONFIG_INET_TUNNEL=y
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
CONFIG_INET_XFRM_MODE_BEET=y
CONFIG_INET_LRO=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
@@ -304,6 +308,7 @@ CONFIG_NET_TCPPROBE=m
#
# Generic Driver Options
#
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_STANDALONE=y
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
CONFIG_FW_LOADER=y
@@ -355,6 +360,11 @@ CONFIG_IDE_PROC_FS=y
# IDE chipset support/bugfixes
#
CONFIG_IDE_GENERIC=y
# CONFIG_BLK_DEV_PLATFORM is not set
#
# PCI IDE chipsets support
#
CONFIG_BLK_DEV_IDEPCI=y
# CONFIG_IDEPCI_SHARE_IRQ is not set
CONFIG_IDEPCI_PCIBUS_ORDER=y
@@ -391,7 +401,6 @@ CONFIG_BLK_DEV_ALI15X3=y
# CONFIG_BLK_DEV_TC86C001 is not set
# CONFIG_IDE_ARM is not set
CONFIG_BLK_DEV_IDEDMA=y
# CONFIG_IDEDMA_IVB is not set
# CONFIG_BLK_DEV_HD is not set
#
@@ -505,6 +514,8 @@ CONFIG_DUMMY=m
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
# CONFIG_VETH is not set
# CONFIG_IP1000 is not set
# CONFIG_ARCNET is not set
# CONFIG_PHYLIB is not set
CONFIG_NET_ETHERNET=y
@@ -518,13 +529,16 @@ CONFIG_CASSINI=m
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
# CONFIG_IBM_NEW_EMAC_ZMII is not set
# CONFIG_IBM_NEW_EMAC_RGMII is not set
# CONFIG_IBM_NEW_EMAC_TAH is not set
# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
# CONFIG_AMD8111_ETH is not set
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_B44 is not set
# CONFIG_FORCEDETH is not set
# CONFIG_DGRS is not set
# CONFIG_EEPRO100 is not set
# CONFIG_E100 is not set
# CONFIG_FEALNX is not set
@@ -543,6 +557,7 @@ CONFIG_NETDEV_1000=y
CONFIG_E1000=m
CONFIG_E1000_NAPI=y
# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
# CONFIG_E1000E is not set
# CONFIG_MYRI_SBUS is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
@@ -560,11 +575,14 @@ CONFIG_BNX2=m
CONFIG_NETDEV_10000=y
# CONFIG_CHELSIO_T1 is not set
# CONFIG_CHELSIO_T3 is not set
# CONFIG_IXGBE is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
# CONFIG_MYRI10GE is not set
# CONFIG_NETXEN_NIC is not set
# CONFIG_NIU is not set
# CONFIG_MLX4_CORE is not set
# CONFIG_TEHUTI is not set
# CONFIG_TR is not set
#
@@ -819,6 +837,12 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_W83627EHF is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Sonics Silicon Backplane
#
CONFIG_SSB_POSSIBLE=y
# CONFIG_SSB is not set
#
# Multifunction device drivers
#
@@ -1399,6 +1423,7 @@ CONFIG_ASYNC_MEMCPY=m
CONFIG_ASYNC_XOR=m
CONFIG_CRYPTO=y
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_AEAD=m
CONFIG_CRYPTO_BLKCIPHER=y
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_MANAGER=y
@@ -1417,6 +1442,7 @@ CONFIG_CRYPTO_ECB=m
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_XTS=m
# CONFIG_CRYPTO_CRYPTD is not set
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_FCRYPT=m
@@ -1431,11 +1457,13 @@ CONFIG_CRYPTO_TEA=m
CONFIG_CRYPTO_ARC4=m
CONFIG_CRYPTO_KHAZAD=m
CONFIG_CRYPTO_ANUBIS=m
CONFIG_CRYPTO_SEED=m
CONFIG_CRYPTO_DEFLATE=y
CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_CRC32C=m
CONFIG_CRYPTO_CAMELLIA=m
CONFIG_CRYPTO_TEST=m
CONFIG_CRYPTO_AUTHENC=m
CONFIG_CRYPTO_HW=y
#
+1
View File
@@ -18,6 +18,7 @@ obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o \
pci_psycho.o pci_sabre.o pci_schizo.o \
pci_sun4v.o pci_sun4v_asm.o pci_fire.o
obj-$(CONFIG_PCI_MSI) += pci_msi.o
obj-$(CONFIG_SMP) += smp.o trampoline.o hvtramp.o
obj-$(CONFIG_SPARC32_COMPAT) += sys32.o sys_sparc32.o signal32.o
obj-$(CONFIG_BINFMT_ELF32) += binfmt_elf32.o
+3 -1
View File
@@ -148,9 +148,11 @@ static int __devinit auxio_probe(struct of_device *dev, const struct of_device_i
}
static struct of_platform_driver auxio_driver = {
.name = "auxio",
.match_table = auxio_match,
.probe = auxio_probe,
.driver = {
.name = "auxio",
},
};
static int __init auxio_init(void)
+7 -7
View File
@@ -429,16 +429,16 @@ do_ivec:
stxa %g0, [%g0] ASI_INTR_RECEIVE
membar #Sync
sethi %hi(ivector_table), %g2
sllx %g3, 3, %g3
or %g2, %lo(ivector_table), %g2
sethi %hi(ivector_table_pa), %g2
ldx [%g2 + %lo(ivector_table_pa)], %g2
sllx %g3, 4, %g3
add %g2, %g3, %g3
TRAP_LOAD_IRQ_WORK(%g6, %g1)
TRAP_LOAD_IRQ_WORK_PA(%g6, %g1)
lduw [%g6], %g5 /* g5 = irq_work(cpu) */
stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */
stw %g3, [%g6] /* irq_work(cpu) = bucket */
ldx [%g6], %g5
stxa %g5, [%g3] ASI_PHYS_USE_EC
stx %g3, [%g6]
wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint
retry
do_ivec_xcall:
+264 -340
View File
File diff suppressed because it is too large Load Diff
+4 -1
View File
@@ -872,7 +872,10 @@ __setup("of_debug=", of_debug);
int of_register_driver(struct of_platform_driver *drv, struct bus_type *bus)
{
/* initialize common driver fields */
drv->driver.name = drv->name;
if (!drv->driver.name)
drv->driver.name = drv->name;
if (!drv->driver.owner)
drv->driver.owner = drv->owner;
drv->driver.bus = bus;
/* register with core */
+30 -30
View File
@@ -29,8 +29,6 @@
#include "pci_impl.h"
unsigned long pci_memspace_mask = 0xffffffffUL;
#ifndef CONFIG_PCI
/* A "nop" PCI implementation. */
asmlinkage int sys_pciconfig_read(unsigned long bus, unsigned long dfn,
@@ -1066,8 +1064,8 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc
return 0;
}
/* Adjust vm_pgoff of VMA such that it is the physical page offset corresponding
* to the 32-bit pci bus offset for DEV requested by the user.
/* Adjust vm_pgoff of VMA such that it is the physical page offset
* corresponding to the 32-bit pci bus offset for DEV requested by the user.
*
* Basically, the user finds the base address for his device which he wishes
* to mmap. They read the 32-bit value from the config space base register,
@@ -1076,21 +1074,35 @@ static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struc
*
* Returns negative error code on failure, zero on success.
*/
static int __pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
static int __pci_mmap_make_offset(struct pci_dev *pdev,
struct vm_area_struct *vma,
enum pci_mmap_state mmap_state)
{
unsigned long user_offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long user32 = user_offset & pci_memspace_mask;
unsigned long largest_base, this_base, addr32;
int i;
unsigned long user_paddr, user_size;
int i, err;
if ((dev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
return __pci_mmap_make_offset_bus(dev, vma, mmap_state);
/* First compute the physical address in vma->vm_pgoff,
* making sure the user offset is within range in the
* appropriate PCI space.
*/
err = __pci_mmap_make_offset_bus(pdev, vma, mmap_state);
if (err)
return err;
/* If this is a mapping on a host bridge, any address
* is OK.
*/
if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
return err;
/* Otherwise make sure it's in the range for one of the
* device's resources.
*/
user_paddr = vma->vm_pgoff << PAGE_SHIFT;
user_size = vma->vm_end - vma->vm_start;
/* Figure out which base address this is for. */
largest_base = 0UL;
for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
struct resource *rp = &dev->resource[i];
struct resource *rp = &pdev->resource[i];
/* Active? */
if (!rp->flags)
@@ -1108,26 +1120,14 @@ static int __pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vm
continue;
}
this_base = rp->start;
addr32 = (this_base & PAGE_MASK) & pci_memspace_mask;
if (mmap_state == pci_mmap_io)
addr32 &= 0xffffff;
if (addr32 <= user32 && this_base > largest_base)
largest_base = this_base;
if ((rp->start <= user_paddr) &&
(user_paddr + user_size) <= (rp->end + 1UL))
break;
}
if (largest_base == 0UL)
if (i > PCI_ROM_RESOURCE)
return -EINVAL;
/* Now construct the final physical address. */
if (mmap_state == pci_mmap_io)
vma->vm_pgoff = (((largest_base & ~0xffffffUL) | user32) >> PAGE_SHIFT);
else
vma->vm_pgoff = (((largest_base & ~(pci_memspace_mask)) | user32) >> PAGE_SHIFT);
return 0;
}
+271 -8
View File
@@ -6,9 +6,12 @@
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/msi.h>
#include <linux/irq.h>
#include <asm/oplib.h>
#include <asm/prom.h>
#include <asm/irq.h>
#include "pci_impl.h"
@@ -84,6 +87,266 @@ static int pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm)
return 0;
}
#ifdef CONFIG_PCI_MSI
struct pci_msiq_entry {
u64 word0;
#define MSIQ_WORD0_RESV 0x8000000000000000UL
#define MSIQ_WORD0_FMT_TYPE 0x7f00000000000000UL
#define MSIQ_WORD0_FMT_TYPE_SHIFT 56
#define MSIQ_WORD0_LEN 0x00ffc00000000000UL
#define MSIQ_WORD0_LEN_SHIFT 46
#define MSIQ_WORD0_ADDR0 0x00003fff00000000UL
#define MSIQ_WORD0_ADDR0_SHIFT 32
#define MSIQ_WORD0_RID 0x00000000ffff0000UL
#define MSIQ_WORD0_RID_SHIFT 16
#define MSIQ_WORD0_DATA0 0x000000000000ffffUL
#define MSIQ_WORD0_DATA0_SHIFT 0
#define MSIQ_TYPE_MSG 0x6
#define MSIQ_TYPE_MSI32 0xb
#define MSIQ_TYPE_MSI64 0xf
u64 word1;
#define MSIQ_WORD1_ADDR1 0xffffffffffff0000UL
#define MSIQ_WORD1_ADDR1_SHIFT 16
#define MSIQ_WORD1_DATA1 0x000000000000ffffUL
#define MSIQ_WORD1_DATA1_SHIFT 0
u64 resv[6];
};
/* All MSI registers are offset from pbm->pbm_regs */
#define EVENT_QUEUE_BASE_ADDR_REG 0x010000UL
#define EVENT_QUEUE_BASE_ADDR_ALL_ONES 0xfffc000000000000UL
#define EVENT_QUEUE_CONTROL_SET(EQ) (0x011000UL + (EQ) * 0x8UL)
#define EVENT_QUEUE_CONTROL_SET_OFLOW 0x0200000000000000UL
#define EVENT_QUEUE_CONTROL_SET_EN 0x0000100000000000UL
#define EVENT_QUEUE_CONTROL_CLEAR(EQ) (0x011200UL + (EQ) * 0x8UL)
#define EVENT_QUEUE_CONTROL_CLEAR_OF 0x0200000000000000UL
#define EVENT_QUEUE_CONTROL_CLEAR_E2I 0x0000800000000000UL
#define EVENT_QUEUE_CONTROL_CLEAR_DIS 0x0000100000000000UL
#define EVENT_QUEUE_STATE(EQ) (0x011400UL + (EQ) * 0x8UL)
#define EVENT_QUEUE_STATE_MASK 0x0000000000000007UL
#define EVENT_QUEUE_STATE_IDLE 0x0000000000000001UL
#define EVENT_QUEUE_STATE_ACTIVE 0x0000000000000002UL
#define EVENT_QUEUE_STATE_ERROR 0x0000000000000004UL
#define EVENT_QUEUE_TAIL(EQ) (0x011600UL + (EQ) * 0x8UL)
#define EVENT_QUEUE_TAIL_OFLOW 0x0200000000000000UL
#define EVENT_QUEUE_TAIL_VAL 0x000000000000007fUL
#define EVENT_QUEUE_HEAD(EQ) (0x011800UL + (EQ) * 0x8UL)
#define EVENT_QUEUE_HEAD_VAL 0x000000000000007fUL
#define MSI_MAP(MSI) (0x020000UL + (MSI) * 0x8UL)
#define MSI_MAP_VALID 0x8000000000000000UL
#define MSI_MAP_EQWR_N 0x4000000000000000UL
#define MSI_MAP_EQNUM 0x000000000000003fUL
#define MSI_CLEAR(MSI) (0x028000UL + (MSI) * 0x8UL)
#define MSI_CLEAR_EQWR_N 0x4000000000000000UL
#define IMONDO_DATA0 0x02C000UL
#define IMONDO_DATA0_DATA 0xffffffffffffffc0UL
#define IMONDO_DATA1 0x02C008UL
#define IMONDO_DATA1_DATA 0xffffffffffffffffUL
#define MSI_32BIT_ADDR 0x034000UL
#define MSI_32BIT_ADDR_VAL 0x00000000ffff0000UL
#define MSI_64BIT_ADDR 0x034008UL
#define MSI_64BIT_ADDR_VAL 0xffffffffffff0000UL
static int pci_fire_get_head(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long *head)
{
*head = fire_read(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid));
return 0;
}
static int pci_fire_dequeue_msi(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long *head, unsigned long *msi)
{
unsigned long type_fmt, type, msi_num;
struct pci_msiq_entry *base, *ep;
base = (pbm->msi_queues + ((msiqid - pbm->msiq_first) * 8192));
ep = &base[*head];
if ((ep->word0 & MSIQ_WORD0_FMT_TYPE) == 0)
return 0;
type_fmt = ((ep->word0 & MSIQ_WORD0_FMT_TYPE) >>
MSIQ_WORD0_FMT_TYPE_SHIFT);
type = (type_fmt >> 3);
if (unlikely(type != MSIQ_TYPE_MSI32 &&
type != MSIQ_TYPE_MSI64))
return -EINVAL;
*msi = msi_num = ((ep->word0 & MSIQ_WORD0_DATA0) >>
MSIQ_WORD0_DATA0_SHIFT);
fire_write(pbm->pbm_regs + MSI_CLEAR(msi_num),
MSI_CLEAR_EQWR_N);
/* Clear the entry. */
ep->word0 &= ~MSIQ_WORD0_FMT_TYPE;
/* Go to next entry in ring. */
(*head)++;
if (*head >= pbm->msiq_ent_count)
*head = 0;
return 1;
}
static int pci_fire_set_head(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long head)
{
fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(msiqid), head);
return 0;
}
static int pci_fire_msi_setup(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long msi, int is_msi64)
{
u64 val;
val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
val &= ~(MSI_MAP_EQNUM);
val |= msiqid;
fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
fire_write(pbm->pbm_regs + MSI_CLEAR(msi),
MSI_CLEAR_EQWR_N);
val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
val |= MSI_MAP_VALID;
fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
return 0;
}
static int pci_fire_msi_teardown(struct pci_pbm_info *pbm, unsigned long msi)
{
unsigned long msiqid;
u64 val;
val = fire_read(pbm->pbm_regs + MSI_MAP(msi));
msiqid = (val & MSI_MAP_EQNUM);
val &= ~MSI_MAP_VALID;
fire_write(pbm->pbm_regs + MSI_MAP(msi), val);
return 0;
}
static int pci_fire_msiq_alloc(struct pci_pbm_info *pbm)
{
unsigned long pages, order, i;
order = get_order(512 * 1024);
pages = __get_free_pages(GFP_KERNEL | __GFP_COMP, order);
if (pages == 0UL) {
printk(KERN_ERR "MSI: Cannot allocate MSI queues (o=%lu).\n",
order);
return -ENOMEM;
}
memset((char *)pages, 0, PAGE_SIZE << order);
pbm->msi_queues = (void *) pages;
fire_write(pbm->pbm_regs + EVENT_QUEUE_BASE_ADDR_REG,
(EVENT_QUEUE_BASE_ADDR_ALL_ONES |
__pa(pbm->msi_queues)));
fire_write(pbm->pbm_regs + IMONDO_DATA0,
pbm->portid << 6);
fire_write(pbm->pbm_regs + IMONDO_DATA1, 0);
fire_write(pbm->pbm_regs + MSI_32BIT_ADDR,
pbm->msi32_start);
fire_write(pbm->pbm_regs + MSI_64BIT_ADDR,
pbm->msi64_start);
for (i = 0; i < pbm->msiq_num; i++) {
fire_write(pbm->pbm_regs + EVENT_QUEUE_HEAD(i), 0);
fire_write(pbm->pbm_regs + EVENT_QUEUE_TAIL(i), 0);
}
return 0;
}
static void pci_fire_msiq_free(struct pci_pbm_info *pbm)
{
unsigned long pages, order;
order = get_order(512 * 1024);
pages = (unsigned long) pbm->msi_queues;
free_pages(pages, order);
pbm->msi_queues = NULL;
}
static int pci_fire_msiq_build_irq(struct pci_pbm_info *pbm,
unsigned long msiqid,
unsigned long devino)
{
unsigned long cregs = (unsigned long) pbm->pbm_regs;
unsigned long imap_reg, iclr_reg, int_ctrlr;
unsigned int virt_irq;
int fixup;
u64 val;
imap_reg = cregs + (0x001000UL + (devino * 0x08UL));
iclr_reg = cregs + (0x001400UL + (devino * 0x08UL));
/* XXX iterate amongst the 4 IRQ controllers XXX */
int_ctrlr = (1UL << 6);
val = fire_read(imap_reg);
val |= (1UL << 63) | int_ctrlr;
fire_write(imap_reg, val);
fixup = ((pbm->portid << 6) | devino) - int_ctrlr;
virt_irq = build_irq(fixup, iclr_reg, imap_reg);
if (!virt_irq)
return -ENOMEM;
fire_write(pbm->pbm_regs +
EVENT_QUEUE_CONTROL_SET(msiqid),
EVENT_QUEUE_CONTROL_SET_EN);
return virt_irq;
}
static const struct sparc64_msiq_ops pci_fire_msiq_ops = {
.get_head = pci_fire_get_head,
.dequeue_msi = pci_fire_dequeue_msi,
.set_head = pci_fire_set_head,
.msi_setup = pci_fire_msi_setup,
.msi_teardown = pci_fire_msi_teardown,
.msiq_alloc = pci_fire_msiq_alloc,
.msiq_free = pci_fire_msiq_free,
.msiq_build_irq = pci_fire_msiq_build_irq,
};
static void pci_fire_msi_init(struct pci_pbm_info *pbm)
{
sparc64_pbm_msi_init(pbm, &pci_fire_msiq_ops);
}
#else /* CONFIG_PCI_MSI */
static void pci_fire_msi_init(struct pci_pbm_info *pbm)
{
}
#endif /* !(CONFIG_PCI_MSI) */
/* Based at pbm->controller_regs */
#define FIRE_PARITY_CONTROL 0x470010UL
#define FIRE_PARITY_ENAB 0x8000000000000000UL
@@ -176,6 +439,7 @@ static int pci_fire_pbm_init(struct pci_controller_info *p,
{
const struct linux_prom64_registers *regs;
struct pci_pbm_info *pbm;
int err;
if ((portid & 1) == 0)
pbm = &p->pbm_A;
@@ -208,7 +472,13 @@ static int pci_fire_pbm_init(struct pci_controller_info *p,
pci_fire_hw_init(pbm);
return pci_fire_pbm_iommu_init(pbm);
err = pci_fire_pbm_iommu_init(pbm);
if (err)
return err;
pci_fire_msi_init(pbm);
return 0;
}
static inline int portid_compare(u32 x, u32 y)
@@ -249,13 +519,6 @@ void fire_pci_init(struct device_node *dp, const char *model_name)
p->pbm_B.iommu = iommu;
/* XXX MSI support XXX */
/* Like PSYCHO and SCHIZO we have a 2GB aligned area
* for memory space.
*/
pci_memspace_mask = 0x7fffffffUL;
if (pci_fire_pbm_init(p, dp, portid))
goto fatal_memory_error;
+31 -1
View File
@@ -29,6 +29,33 @@
#define PCI_STC_FLUSHFLAG_SET(STC) \
(*((STC)->strbuf_flushflag) != 0UL)
#ifdef CONFIG_PCI_MSI
struct pci_pbm_info;
struct sparc64_msiq_ops {
int (*get_head)(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long *head);
int (*dequeue_msi)(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long *head, unsigned long *msi);
int (*set_head)(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long head);
int (*msi_setup)(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long msi, int is_msi64);
int (*msi_teardown)(struct pci_pbm_info *pbm, unsigned long msi);
int (*msiq_alloc)(struct pci_pbm_info *pbm);
void (*msiq_free)(struct pci_pbm_info *pbm);
int (*msiq_build_irq)(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long devino);
};
extern void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
const struct sparc64_msiq_ops *ops);
struct sparc64_msiq_cookie {
struct pci_pbm_info *pbm;
unsigned long msiqid;
};
#endif
struct pci_controller_info;
struct pci_pbm_info {
@@ -90,6 +117,8 @@ struct pci_pbm_info {
u32 msiq_ent_count;
u32 msiq_first;
u32 msiq_first_devino;
u32 msiq_rotor;
struct sparc64_msiq_cookie *msiq_irq_cookies;
u32 msi_num;
u32 msi_first;
u32 msi_data_mask;
@@ -100,9 +129,11 @@ struct pci_pbm_info {
u32 msi64_len;
void *msi_queues;
unsigned long *msi_bitmap;
unsigned int *msi_irq_table;
int (*setup_msi_irq)(unsigned int *virt_irq_p, struct pci_dev *pdev,
struct msi_desc *entry);
void (*teardown_msi_irq)(unsigned int virt_irq, struct pci_dev *pdev);
const struct sparc64_msiq_ops *msi_ops;
#endif /* !(CONFIG_PCI_MSI) */
/* This PBM's streaming buffer. */
@@ -126,7 +157,6 @@ struct pci_controller_info {
};
extern struct pci_pbm_info *pci_pbm_root;
extern unsigned long pci_memspace_mask;
extern int pci_num_pbms;
+433
View File
@@ -0,0 +1,433 @@
/* pci_msi.c: Sparc64 MSI support common layer.
*
* Copyright (C) 2007 David S. Miller (davem@davemloft.net)
*/
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include "pci_impl.h"
static irqreturn_t sparc64_msiq_interrupt(int irq, void *cookie)
{
struct sparc64_msiq_cookie *msiq_cookie = cookie;
struct pci_pbm_info *pbm = msiq_cookie->pbm;
unsigned long msiqid = msiq_cookie->msiqid;
const struct sparc64_msiq_ops *ops;
unsigned long orig_head, head;
int err;
ops = pbm->msi_ops;
err = ops->get_head(pbm, msiqid, &head);
if (unlikely(err < 0))
goto err_get_head;
orig_head = head;
for (;;) {
unsigned long msi;
err = ops->dequeue_msi(pbm, msiqid, &head, &msi);
if (likely(err > 0))
__do_IRQ(pbm->msi_irq_table[msi - pbm->msi_first]);
if (unlikely(err < 0))
goto err_dequeue;
if (err == 0)
break;
}
if (likely(head != orig_head)) {
err = ops->set_head(pbm, msiqid, head);
if (unlikely(err < 0))
goto err_set_head;
}
return IRQ_HANDLED;
err_get_head:
printk(KERN_EMERG "MSI: Get head on msiqid[%lu] gives error %d\n",
msiqid, err);
goto err_out;
err_dequeue:
printk(KERN_EMERG "MSI: Dequeue head[%lu] from msiqid[%lu] "
"gives error %d\n",
head, msiqid, err);
goto err_out;
err_set_head:
printk(KERN_EMERG "MSI: Set head[%lu] on msiqid[%lu] "
"gives error %d\n",
head, msiqid, err);
goto err_out;
err_out:
return IRQ_NONE;
}
static u32 pick_msiq(struct pci_pbm_info *pbm)
{
static DEFINE_SPINLOCK(rotor_lock);
unsigned long flags;
u32 ret, rotor;
spin_lock_irqsave(&rotor_lock, flags);
rotor = pbm->msiq_rotor;
ret = pbm->msiq_first + rotor;
if (++rotor >= pbm->msiq_num)
rotor = 0;
pbm->msiq_rotor = rotor;
spin_unlock_irqrestore(&rotor_lock, flags);
return ret;
}
static int alloc_msi(struct pci_pbm_info *pbm)
{
int i;
for (i = 0; i < pbm->msi_num; i++) {
if (!test_and_set_bit(i, pbm->msi_bitmap))
return i + pbm->msi_first;
}
return -ENOENT;
}
static void free_msi(struct pci_pbm_info *pbm, int msi_num)
{
msi_num -= pbm->msi_first;
clear_bit(msi_num, pbm->msi_bitmap);
}
static struct irq_chip msi_irq = {
.typename = "PCI-MSI",
.mask = mask_msi_irq,
.unmask = unmask_msi_irq,
.enable = unmask_msi_irq,
.disable = mask_msi_irq,
/* XXX affinity XXX */
};
int sparc64_setup_msi_irq(unsigned int *virt_irq_p,
struct pci_dev *pdev,
struct msi_desc *entry)
{
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
const struct sparc64_msiq_ops *ops = pbm->msi_ops;
struct msi_msg msg;
int msi, err;
u32 msiqid;
*virt_irq_p = virt_irq_alloc(0, 0);
err = -ENOMEM;
if (!*virt_irq_p)
goto out_err;
set_irq_chip(*virt_irq_p, &msi_irq);
err = alloc_msi(pbm);
if (unlikely(err < 0))
goto out_virt_irq_free;
msi = err;
msiqid = pick_msiq(pbm);
err = ops->msi_setup(pbm, msiqid, msi,
(entry->msi_attrib.is_64 ? 1 : 0));
if (err)
goto out_msi_free;
pbm->msi_irq_table[msi - pbm->msi_first] = *virt_irq_p;
if (entry->msi_attrib.is_64) {
msg.address_hi = pbm->msi64_start >> 32;
msg.address_lo = pbm->msi64_start & 0xffffffff;
} else {
msg.address_hi = 0;
msg.address_lo = pbm->msi32_start;
}
msg.data = msi;
set_irq_msi(*virt_irq_p, entry);
write_msi_msg(*virt_irq_p, &msg);
return 0;
out_msi_free:
free_msi(pbm, msi);
out_virt_irq_free:
set_irq_chip(*virt_irq_p, NULL);
virt_irq_free(*virt_irq_p);
*virt_irq_p = 0;
out_err:
return err;
}
void sparc64_teardown_msi_irq(unsigned int virt_irq,
struct pci_dev *pdev)
{
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
const struct sparc64_msiq_ops *ops = pbm->msi_ops;
unsigned int msi_num;
int i, err;
for (i = 0; i < pbm->msi_num; i++) {
if (pbm->msi_irq_table[i] == virt_irq)
break;
}
if (i >= pbm->msi_num) {
printk(KERN_ERR "%s: teardown: No MSI for irq %u\n",
pbm->name, virt_irq);
return;
}
msi_num = pbm->msi_first + i;
pbm->msi_irq_table[i] = ~0U;
err = ops->msi_teardown(pbm, msi_num);
if (err) {
printk(KERN_ERR "%s: teardown: ops->teardown() on MSI %u, "
"irq %u, gives error %d\n",
pbm->name, msi_num, virt_irq, err);
return;
}
free_msi(pbm, msi_num);
set_irq_chip(virt_irq, NULL);
virt_irq_free(virt_irq);
}
static int msi_bitmap_alloc(struct pci_pbm_info *pbm)
{
unsigned long size, bits_per_ulong;
bits_per_ulong = sizeof(unsigned long) * 8;
size = (pbm->msi_num + (bits_per_ulong - 1)) & ~(bits_per_ulong - 1);
size /= 8;
BUG_ON(size % sizeof(unsigned long));
pbm->msi_bitmap = kzalloc(size, GFP_KERNEL);
if (!pbm->msi_bitmap)
return -ENOMEM;
return 0;
}
static void msi_bitmap_free(struct pci_pbm_info *pbm)
{
kfree(pbm->msi_bitmap);
pbm->msi_bitmap = NULL;
}
static int msi_table_alloc(struct pci_pbm_info *pbm)
{
int size, i;
size = pbm->msiq_num * sizeof(struct sparc64_msiq_cookie);
pbm->msiq_irq_cookies = kzalloc(size, GFP_KERNEL);
if (!pbm->msiq_irq_cookies)
return -ENOMEM;
for (i = 0; i < pbm->msiq_num; i++) {
struct sparc64_msiq_cookie *p;
p = &pbm->msiq_irq_cookies[i];
p->pbm = pbm;
p->msiqid = pbm->msiq_first + i;
}
size = pbm->msi_num * sizeof(unsigned int);
pbm->msi_irq_table = kzalloc(size, GFP_KERNEL);
if (!pbm->msi_irq_table) {
kfree(pbm->msiq_irq_cookies);
pbm->msiq_irq_cookies = NULL;
return -ENOMEM;
}
return 0;
}
static void msi_table_free(struct pci_pbm_info *pbm)
{
kfree(pbm->msiq_irq_cookies);
pbm->msiq_irq_cookies = NULL;
kfree(pbm->msi_irq_table);
pbm->msi_irq_table = NULL;
}
static int bringup_one_msi_queue(struct pci_pbm_info *pbm,
const struct sparc64_msiq_ops *ops,
unsigned long msiqid,
unsigned long devino)
{
int irq = ops->msiq_build_irq(pbm, msiqid, devino);
int err;
if (irq < 0)
return irq;
err = request_irq(irq, sparc64_msiq_interrupt, 0,
"MSIQ",
&pbm->msiq_irq_cookies[msiqid - pbm->msiq_first]);
if (err)
return err;
return 0;
}
static int sparc64_bringup_msi_queues(struct pci_pbm_info *pbm,
const struct sparc64_msiq_ops *ops)
{
int i;
for (i = 0; i < pbm->msiq_num; i++) {
unsigned long msiqid = i + pbm->msiq_first;
unsigned long devino = i + pbm->msiq_first_devino;
int err;
err = bringup_one_msi_queue(pbm, ops, msiqid, devino);
if (err)
return err;
}
return 0;
}
void sparc64_pbm_msi_init(struct pci_pbm_info *pbm,
const struct sparc64_msiq_ops *ops)
{
const u32 *val;
int len;
val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
if (!val || len != 4)
goto no_msi;
pbm->msiq_num = *val;
if (pbm->msiq_num) {
const struct msiq_prop {
u32 first_msiq;
u32 num_msiq;
u32 first_devino;
} *mqp;
const struct msi_range_prop {
u32 first_msi;
u32 num_msi;
} *mrng;
const struct addr_range_prop {
u32 msi32_high;
u32 msi32_low;
u32 msi32_len;
u32 msi64_high;
u32 msi64_low;
u32 msi64_len;
} *arng;
val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
if (!val || len != 4)
goto no_msi;
pbm->msiq_ent_count = *val;
mqp = of_get_property(pbm->prom_node,
"msi-eq-to-devino", &len);
if (!mqp)
mqp = of_get_property(pbm->prom_node,
"msi-eq-devino", &len);
if (!mqp || len != sizeof(struct msiq_prop))
goto no_msi;
pbm->msiq_first = mqp->first_msiq;
pbm->msiq_first_devino = mqp->first_devino;
val = of_get_property(pbm->prom_node, "#msi", &len);
if (!val || len != 4)
goto no_msi;
pbm->msi_num = *val;
mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
if (!mrng || len != sizeof(struct msi_range_prop))
goto no_msi;
pbm->msi_first = mrng->first_msi;
val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
if (!val || len != 4)
goto no_msi;
pbm->msi_data_mask = *val;
val = of_get_property(pbm->prom_node, "msix-data-width", &len);
if (!val || len != 4)
goto no_msi;
pbm->msix_data_width = *val;
arng = of_get_property(pbm->prom_node, "msi-address-ranges",
&len);
if (!arng || len != sizeof(struct addr_range_prop))
goto no_msi;
pbm->msi32_start = ((u64)arng->msi32_high << 32) |
(u64) arng->msi32_low;
pbm->msi64_start = ((u64)arng->msi64_high << 32) |
(u64) arng->msi64_low;
pbm->msi32_len = arng->msi32_len;
pbm->msi64_len = arng->msi64_len;
if (msi_bitmap_alloc(pbm))
goto no_msi;
if (msi_table_alloc(pbm)) {
msi_bitmap_free(pbm);
goto no_msi;
}
if (ops->msiq_alloc(pbm)) {
msi_table_free(pbm);
msi_bitmap_free(pbm);
goto no_msi;
}
if (sparc64_bringup_msi_queues(pbm, ops)) {
ops->msiq_free(pbm);
msi_table_free(pbm);
msi_bitmap_free(pbm);
goto no_msi;
}
printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
"devino[0x%x]\n",
pbm->name,
pbm->msiq_first, pbm->msiq_num,
pbm->msiq_ent_count,
pbm->msiq_first_devino);
printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
"width[%u]\n",
pbm->name,
pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
pbm->msix_data_width);
printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
"addr64[0x%lx:0x%x]\n",
pbm->name,
pbm->msi32_start, pbm->msi32_len,
pbm->msi64_start, pbm->msi64_len);
printk(KERN_INFO "%s: MSI queues at RA [%016lx]\n",
pbm->name,
__pa(pbm->msi_queues));
pbm->msi_ops = ops;
pbm->setup_msi_irq = sparc64_setup_msi_irq;
pbm->teardown_msi_irq = sparc64_teardown_msi_irq;
}
return;
no_msi:
pbm->msiq_num = 0;
printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
}
-6
View File
@@ -1058,12 +1058,6 @@ void psycho_init(struct device_node *dp, char *model_name)
p->pbm_A.config_space = p->pbm_B.config_space =
(pr_regs[2].phys_addr + PSYCHO_CONFIGSPACE);
/*
* Psycho's PCI MEM space is mapped to a 2GB aligned area, so
* we need to adjust our MEM space mask.
*/
pci_memspace_mask = 0x7fffffffUL;
psycho_controller_hwinit(&p->pbm_A);
if (psycho_iommu_init(&p->pbm_A))
-3
View File
@@ -1464,9 +1464,6 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ
p->pbm_B.iommu = iommu;
/* Like PSYCHO we have a 2GB aligned area for memory space. */
pci_memspace_mask = 0x7fffffffUL;
if (schizo_pbm_init(p, dp, portid, chip_type))
goto fatal_memory_error;
+120 -307
View File
@@ -748,111 +748,102 @@ struct pci_sun4v_msiq_entry {
u64 reserved2;
};
/* For now this just runs as a pre-handler for the real interrupt handler.
* So we just walk through the queue and ACK all the entries, update the
* head pointer, and return.
*
* In the longer term it would be nice to do something more integrated
* wherein we can pass in some of this MSI info to the drivers. This
* would be most useful for PCIe fabric error messages, although we could
* invoke those directly from the loop here in order to pass the info around.
*/
static void pci_sun4v_msi_prehandler(unsigned int ino, void *data1, void *data2)
static int pci_sun4v_get_head(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long *head)
{
struct pci_pbm_info *pbm = data1;
struct pci_sun4v_msiq_entry *base, *ep;
unsigned long msiqid, orig_head, head, type, err;
unsigned long err, limit;
msiqid = (unsigned long) data2;
head = 0xdeadbeef;
err = pci_sun4v_msiq_gethead(pbm->devhandle, msiqid, &head);
err = pci_sun4v_msiq_gethead(pbm->devhandle, msiqid, head);
if (unlikely(err))
goto hv_error_get;
return -ENXIO;
if (unlikely(head >= (pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry))))
goto bad_offset;
head /= sizeof(struct pci_sun4v_msiq_entry);
orig_head = head;
base = (pbm->msi_queues + ((msiqid - pbm->msiq_first) *
(pbm->msiq_ent_count *
sizeof(struct pci_sun4v_msiq_entry))));
ep = &base[head];
while ((ep->version_type & MSIQ_TYPE_MASK) != 0) {
type = (ep->version_type & MSIQ_TYPE_MASK) >> MSIQ_TYPE_SHIFT;
if (unlikely(type != MSIQ_TYPE_MSI32 &&
type != MSIQ_TYPE_MSI64))
goto bad_type;
pci_sun4v_msi_setstate(pbm->devhandle,
ep->msi_data /* msi_num */,
HV_MSISTATE_IDLE);
/* Clear the entry. */
ep->version_type &= ~MSIQ_TYPE_MASK;
/* Go to next entry in ring. */
head++;
if (head >= pbm->msiq_ent_count)
head = 0;
ep = &base[head];
}
if (likely(head != orig_head)) {
/* ACK entries by updating head pointer. */
head *= sizeof(struct pci_sun4v_msiq_entry);
err = pci_sun4v_msiq_sethead(pbm->devhandle, msiqid, head);
if (unlikely(err))
goto hv_error_set;
}
return;
hv_error_set:
printk(KERN_EMERG "MSI: Hypervisor set head gives error %lu\n", err);
goto hv_error_cont;
hv_error_get:
printk(KERN_EMERG "MSI: Hypervisor get head gives error %lu\n", err);
hv_error_cont:
printk(KERN_EMERG "MSI: devhandle[%x] msiqid[%lx] head[%lu]\n",
pbm->devhandle, msiqid, head);
return;
bad_offset:
printk(KERN_EMERG "MSI: Hypervisor gives bad offset %lx max(%lx)\n",
head, pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry));
return;
bad_type:
printk(KERN_EMERG "MSI: Entry has bad type %lx\n", type);
return;
}
static int msi_bitmap_alloc(struct pci_pbm_info *pbm)
{
unsigned long size, bits_per_ulong;
bits_per_ulong = sizeof(unsigned long) * 8;
size = (pbm->msi_num + (bits_per_ulong - 1)) & ~(bits_per_ulong - 1);
size /= 8;
BUG_ON(size % sizeof(unsigned long));
pbm->msi_bitmap = kzalloc(size, GFP_KERNEL);
if (!pbm->msi_bitmap)
return -ENOMEM;
limit = pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry);
if (unlikely(*head >= limit))
return -EFBIG;
return 0;
}
static void msi_bitmap_free(struct pci_pbm_info *pbm)
static int pci_sun4v_dequeue_msi(struct pci_pbm_info *pbm,
unsigned long msiqid, unsigned long *head,
unsigned long *msi)
{
kfree(pbm->msi_bitmap);
pbm->msi_bitmap = NULL;
struct pci_sun4v_msiq_entry *ep;
unsigned long err, type;
/* Note: void pointer arithmetic, 'head' is a byte offset */
ep = (pbm->msi_queues + ((msiqid - pbm->msiq_first) *
(pbm->msiq_ent_count *
sizeof(struct pci_sun4v_msiq_entry))) +
*head);
if ((ep->version_type & MSIQ_TYPE_MASK) == 0)
return 0;
type = (ep->version_type & MSIQ_TYPE_MASK) >> MSIQ_TYPE_SHIFT;
if (unlikely(type != MSIQ_TYPE_MSI32 &&
type != MSIQ_TYPE_MSI64))
return -EINVAL;
*msi = ep->msi_data;
err = pci_sun4v_msi_setstate(pbm->devhandle,
ep->msi_data /* msi_num */,
HV_MSISTATE_IDLE);
if (unlikely(err))
return -ENXIO;
/* Clear the entry. */
ep->version_type &= ~MSIQ_TYPE_MASK;
(*head) += sizeof(struct pci_sun4v_msiq_entry);
if (*head >=
(pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry)))
*head = 0;
return 1;
}
static int msi_queue_alloc(struct pci_pbm_info *pbm)
static int pci_sun4v_set_head(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long head)
{
unsigned long err;
err = pci_sun4v_msiq_sethead(pbm->devhandle, msiqid, head);
if (unlikely(err))
return -EINVAL;
return 0;
}
static int pci_sun4v_msi_setup(struct pci_pbm_info *pbm, unsigned long msiqid,
unsigned long msi, int is_msi64)
{
if (pci_sun4v_msi_setmsiq(pbm->devhandle, msi, msiqid,
(is_msi64 ?
HV_MSITYPE_MSI64 : HV_MSITYPE_MSI32)))
return -ENXIO;
if (pci_sun4v_msi_setstate(pbm->devhandle, msi, HV_MSISTATE_IDLE))
return -ENXIO;
if (pci_sun4v_msi_setvalid(pbm->devhandle, msi, HV_MSIVALID_VALID))
return -ENXIO;
return 0;
}
static int pci_sun4v_msi_teardown(struct pci_pbm_info *pbm, unsigned long msi)
{
unsigned long err, msiqid;
err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi, &msiqid);
if (err)
return -ENXIO;
pci_sun4v_msi_setvalid(pbm->devhandle, msi, HV_MSIVALID_INVALID);
return 0;
}
static int pci_sun4v_msiq_alloc(struct pci_pbm_info *pbm)
{
unsigned long q_size, alloc_size, pages, order;
int i;
@@ -906,232 +897,59 @@ h_error:
return -EINVAL;
}
static int alloc_msi(struct pci_pbm_info *pbm)
static void pci_sun4v_msiq_free(struct pci_pbm_info *pbm)
{
unsigned long q_size, alloc_size, pages, order;
int i;
for (i = 0; i < pbm->msi_num; i++) {
if (!test_and_set_bit(i, pbm->msi_bitmap))
return i + pbm->msi_first;
for (i = 0; i < pbm->msiq_num; i++) {
unsigned long msiqid = pbm->msiq_first + i;
(void) pci_sun4v_msiq_conf(pbm->devhandle, msiqid, 0UL, 0);
}
return -ENOENT;
q_size = pbm->msiq_ent_count * sizeof(struct pci_sun4v_msiq_entry);
alloc_size = (pbm->msiq_num * q_size);
order = get_order(alloc_size);
pages = (unsigned long) pbm->msi_queues;
free_pages(pages, order);
pbm->msi_queues = NULL;
}
static void free_msi(struct pci_pbm_info *pbm, int msi_num)
static int pci_sun4v_msiq_build_irq(struct pci_pbm_info *pbm,
unsigned long msiqid,
unsigned long devino)
{
msi_num -= pbm->msi_first;
clear_bit(msi_num, pbm->msi_bitmap);
}
unsigned int virt_irq = sun4v_build_irq(pbm->devhandle, devino);
static int pci_sun4v_setup_msi_irq(unsigned int *virt_irq_p,
struct pci_dev *pdev,
struct msi_desc *entry)
{
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
unsigned long devino, msiqid;
struct msi_msg msg;
int msi_num, err;
if (!virt_irq)
return -ENOMEM;
*virt_irq_p = 0;
msi_num = alloc_msi(pbm);
if (msi_num < 0)
return msi_num;
err = sun4v_build_msi(pbm->devhandle, virt_irq_p,
pbm->msiq_first_devino,
(pbm->msiq_first_devino +
pbm->msiq_num));
if (err < 0)
goto out_err;
devino = err;
msiqid = ((devino - pbm->msiq_first_devino) +
pbm->msiq_first);
err = -EINVAL;
if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE))
if (err)
goto out_err;
return -EINVAL;
if (pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_VALID))
goto out_err;
if (pci_sun4v_msi_setmsiq(pbm->devhandle,
msi_num, msiqid,
(entry->msi_attrib.is_64 ?
HV_MSITYPE_MSI64 : HV_MSITYPE_MSI32)))
goto out_err;
if (pci_sun4v_msi_setstate(pbm->devhandle, msi_num, HV_MSISTATE_IDLE))
goto out_err;
if (pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_VALID))
goto out_err;
sparc64_set_msi(*virt_irq_p, msi_num);
if (entry->msi_attrib.is_64) {
msg.address_hi = pbm->msi64_start >> 32;
msg.address_lo = pbm->msi64_start & 0xffffffff;
} else {
msg.address_hi = 0;
msg.address_lo = pbm->msi32_start;
}
msg.data = msi_num;
set_irq_msi(*virt_irq_p, entry);
write_msi_msg(*virt_irq_p, &msg);
irq_install_pre_handler(*virt_irq_p,
pci_sun4v_msi_prehandler,
pbm, (void *) msiqid);
return 0;
out_err:
free_msi(pbm, msi_num);
return err;
return -EINVAL;
return virt_irq;
}
static void pci_sun4v_teardown_msi_irq(unsigned int virt_irq,
struct pci_dev *pdev)
{
struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
unsigned long msiqid, err;
unsigned int msi_num;
msi_num = sparc64_get_msi(virt_irq);
err = pci_sun4v_msi_getmsiq(pbm->devhandle, msi_num, &msiqid);
if (err) {
printk(KERN_ERR "%s: getmsiq gives error %lu\n",
pbm->name, err);
return;
}
pci_sun4v_msi_setvalid(pbm->devhandle, msi_num, HV_MSIVALID_INVALID);
pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_INVALID);
free_msi(pbm, msi_num);
/* The sun4v_destroy_msi() will liberate the devino and thus the MSIQ
* allocation.
*/
sun4v_destroy_msi(virt_irq);
}
static const struct sparc64_msiq_ops pci_sun4v_msiq_ops = {
.get_head = pci_sun4v_get_head,
.dequeue_msi = pci_sun4v_dequeue_msi,
.set_head = pci_sun4v_set_head,
.msi_setup = pci_sun4v_msi_setup,
.msi_teardown = pci_sun4v_msi_teardown,
.msiq_alloc = pci_sun4v_msiq_alloc,
.msiq_free = pci_sun4v_msiq_free,
.msiq_build_irq = pci_sun4v_msiq_build_irq,
};
static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
{
const u32 *val;
int len;
val = of_get_property(pbm->prom_node, "#msi-eqs", &len);
if (!val || len != 4)
goto no_msi;
pbm->msiq_num = *val;
if (pbm->msiq_num) {
const struct msiq_prop {
u32 first_msiq;
u32 num_msiq;
u32 first_devino;
} *mqp;
const struct msi_range_prop {
u32 first_msi;
u32 num_msi;
} *mrng;
const struct addr_range_prop {
u32 msi32_high;
u32 msi32_low;
u32 msi32_len;
u32 msi64_high;
u32 msi64_low;
u32 msi64_len;
} *arng;
val = of_get_property(pbm->prom_node, "msi-eq-size", &len);
if (!val || len != 4)
goto no_msi;
pbm->msiq_ent_count = *val;
mqp = of_get_property(pbm->prom_node,
"msi-eq-to-devino", &len);
if (!mqp || len != sizeof(struct msiq_prop))
goto no_msi;
pbm->msiq_first = mqp->first_msiq;
pbm->msiq_first_devino = mqp->first_devino;
val = of_get_property(pbm->prom_node, "#msi", &len);
if (!val || len != 4)
goto no_msi;
pbm->msi_num = *val;
mrng = of_get_property(pbm->prom_node, "msi-ranges", &len);
if (!mrng || len != sizeof(struct msi_range_prop))
goto no_msi;
pbm->msi_first = mrng->first_msi;
val = of_get_property(pbm->prom_node, "msi-data-mask", &len);
if (!val || len != 4)
goto no_msi;
pbm->msi_data_mask = *val;
val = of_get_property(pbm->prom_node, "msix-data-width", &len);
if (!val || len != 4)
goto no_msi;
pbm->msix_data_width = *val;
arng = of_get_property(pbm->prom_node, "msi-address-ranges",
&len);
if (!arng || len != sizeof(struct addr_range_prop))
goto no_msi;
pbm->msi32_start = ((u64)arng->msi32_high << 32) |
(u64) arng->msi32_low;
pbm->msi64_start = ((u64)arng->msi64_high << 32) |
(u64) arng->msi64_low;
pbm->msi32_len = arng->msi32_len;
pbm->msi64_len = arng->msi64_len;
if (msi_bitmap_alloc(pbm))
goto no_msi;
if (msi_queue_alloc(pbm)) {
msi_bitmap_free(pbm);
goto no_msi;
}
printk(KERN_INFO "%s: MSI Queue first[%u] num[%u] count[%u] "
"devino[0x%x]\n",
pbm->name,
pbm->msiq_first, pbm->msiq_num,
pbm->msiq_ent_count,
pbm->msiq_first_devino);
printk(KERN_INFO "%s: MSI first[%u] num[%u] mask[0x%x] "
"width[%u]\n",
pbm->name,
pbm->msi_first, pbm->msi_num, pbm->msi_data_mask,
pbm->msix_data_width);
printk(KERN_INFO "%s: MSI addr32[0x%lx:0x%x] "
"addr64[0x%lx:0x%x]\n",
pbm->name,
pbm->msi32_start, pbm->msi32_len,
pbm->msi64_start, pbm->msi64_len);
printk(KERN_INFO "%s: MSI queues at RA [%p]\n",
pbm->name,
pbm->msi_queues);
}
pbm->setup_msi_irq = pci_sun4v_setup_msi_irq;
pbm->teardown_msi_irq = pci_sun4v_teardown_msi_irq;
return;
no_msi:
pbm->msiq_num = 0;
printk(KERN_INFO "%s: No MSI support.\n", pbm->name);
sparc64_pbm_msi_init(pbm, &pci_sun4v_msiq_ops);
}
#else /* CONFIG_PCI_MSI */
static void pci_sun4v_msi_init(struct pci_pbm_info *pbm)
@@ -1237,11 +1055,6 @@ void __init sun4v_pci_init(struct device_node *dp, char *model_name)
p->pbm_B.iommu = iommu;
/* Like PSYCHO and SCHIZO we have a 2GB aligned area
* for memory space.
*/
pci_memspace_mask = 0x7fffffffUL;
pci_sun4v_pbm_init(p, dp, devhandle);
return;
+3 -1
View File
@@ -105,9 +105,11 @@ static struct of_device_id power_match[] = {
};
static struct of_platform_driver power_driver = {
.name = "power",
.match_table = power_match,
.probe = power_probe,
.driver = {
.name = "power",
},
};
void __init power_init(void)

Some files were not shown because too many files have changed in this diff Show More