From cce933bc831c451f48ca26e5b0d9bfdfbfb327f8 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 25 Jul 2007 16:51:20 -0700 Subject: [SPARC]: Update defconfig. Signed-off-by: David S. Miller --- arch/sparc/defconfig | 186 +++++++++++---------------------------------------- 1 file changed, 40 insertions(+), 146 deletions(-) diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index fdc67238408..f7a50914919 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -1,12 +1,14 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.22-rc1 -# Mon May 14 03:25:14 2007 +# Linux kernel version: 2.6.23-rc1 +# Wed Jul 25 15:30:21 2007 # CONFIG_MMU=y CONFIG_HIGHMEM=y CONFIG_ZONE_DMA=y CONFIG_GENERIC_ISA_DMA=y +CONFIG_ARCH_NO_VIRT_TO_BUS=y +CONFIG_OF=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # @@ -23,12 +25,11 @@ CONFIG_LOCALVERSION="" CONFIG_LOCALVERSION_AUTO=y CONFIG_SWAP=y CONFIG_SYSVIPC=y -# CONFIG_IPC_NS is not set CONFIG_SYSVIPC_SYSCTL=y CONFIG_POSIX_MQUEUE=y # CONFIG_BSD_PROCESS_ACCT is not set # CONFIG_TASKSTATS is not set -# CONFIG_UTS_NS is not set +# CONFIG_USER_NS is not set # CONFIG_AUDIT is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=14 @@ -63,24 +64,17 @@ CONFIG_SLAB=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 - -# -# Loadable module support -# CONFIG_MODULES=y CONFIG_MODULE_UNLOAD=y # CONFIG_MODULE_FORCE_UNLOAD is not set # CONFIG_MODVERSIONS is not set # CONFIG_MODULE_SRCVERSION_ALL is not set CONFIG_KMOD=y - -# -# Block layer -# CONFIG_BLOCK=y # CONFIG_LBD is not set # CONFIG_BLK_DEV_IO_TRACE is not set # CONFIG_LSF is not set +# CONFIG_BLK_DEV_BSG is not set # # IO Schedulers @@ -113,11 +107,14 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y CONFIG_ARCH_MAY_HAVE_PC_FDC=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set +CONFIG_EMULATED_CMPXCHG=y CONFIG_SUN_PM=y # CONFIG_SUN4 is not set CONFIG_PCI=y +CONFIG_PCI_SYSCALL=y # CONFIG_ARCH_SUPPORTS_MSI is not set # CONFIG_PCI_DEBUG is not set +# CONFIG_NO_DMA is not set CONFIG_SUN_OPENPROMFS=m # CONFIG_SPARC_LED is not set CONFIG_BINFMT_ELF=y @@ -134,6 +131,7 @@ CONFIG_FLAT_NODE_MEM_MAP=y CONFIG_SPLIT_PTLOCK_CPUS=4 # CONFIG_RESOURCES_64BIT is not set CONFIG_ZONE_DMA_FLAG=1 +CONFIG_BOUNCE=y # # Networking @@ -197,25 +195,13 @@ CONFIG_IPV6_TUNNEL=m # CONFIG_IPV6_MULTIPLE_TABLES is not set # CONFIG_NETWORK_SECMARK is not set # CONFIG_NETFILTER is not set - -# -# DCCP Configuration (EXPERIMENTAL) -# # CONFIG_IP_DCCP is not set - -# -# SCTP Configuration (EXPERIMENTAL) -# CONFIG_IP_SCTP=m # CONFIG_SCTP_DBG_MSG is not set CONFIG_SCTP_DBG_OBJCNT=y # CONFIG_SCTP_HMAC_NONE is not set # CONFIG_SCTP_HMAC_SHA1 is not set CONFIG_SCTP_HMAC_MD5=y - -# -# TIPC Configuration (EXPERIMENTAL) -# # CONFIG_TIPC is not set # CONFIG_ATM is not set # CONFIG_BRIDGE is not set @@ -253,6 +239,7 @@ CONFIG_AF_RXRPC=m # CONFIG_MAC80211 is not set # CONFIG_IEEE80211 is not set # CONFIG_RFKILL is not set +# CONFIG_NET_9P is not set # # Device Drivers @@ -267,28 +254,12 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y # CONFIG_DEBUG_DRIVER is not set # CONFIG_DEBUG_DEVRES is not set # CONFIG_SYS_HYPERVISOR is not set - -# -# Connector - unified userspace <-> kernelspace linker -# # CONFIG_CONNECTOR is not set # CONFIG_MTD is not set - -# -# Parallel port support -# +CONFIG_OF_DEVICE=y # CONFIG_PARPORT is not set - -# -# Plug and Play support -# -# CONFIG_PNPACPI is not set - -# -# Block devices -# +CONFIG_BLK_DEV=y # CONFIG_BLK_DEV_FD is not set -# CONFIG_BLK_CPQ_DA is not set # CONFIG_BLK_CPQ_CISS_DA is not set # CONFIG_BLK_DEV_DAC960 is not set # CONFIG_BLK_DEV_UMEM is not set @@ -303,18 +274,11 @@ CONFIG_BLK_DEV_RAM_SIZE=4096 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # CONFIG_CDROM_PKTCDVD is not set # CONFIG_ATA_OVER_ETH is not set - -# -# Misc devices -# +CONFIG_MISC_DEVICES=y # CONFIG_PHANTOM is not set +# CONFIG_EEPROM_93CX6 is not set # CONFIG_SGI_IOC4 is not set # CONFIG_TIFM_CORE is not set -# CONFIG_BLINK is not set - -# -# ATA/ATAPI/MFM/RLL support -# # CONFIG_IDE is not set # @@ -322,6 +286,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024 # # CONFIG_RAID_ATTRS is not set CONFIG_SCSI=y +CONFIG_SCSI_DMA=y # CONFIG_SCSI_TGT is not set # CONFIG_SCSI_NETLINK is not set CONFIG_SCSI_PROC_FS=y @@ -352,12 +317,8 @@ CONFIG_SCSI_WAIT_SCAN=m CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_FC_ATTRS is not set # CONFIG_SCSI_ISCSI_ATTRS is not set -# CONFIG_SCSI_SAS_ATTRS is not set # CONFIG_SCSI_SAS_LIBSAS is not set - -# -# SCSI low-level drivers -# +CONFIG_SCSI_LOWLEVEL=y # CONFIG_ISCSI_TCP is not set # CONFIG_BLK_DEV_3W_XXXX_RAID is not set # CONFIG_SCSI_3W_9XXX is not set @@ -367,7 +328,6 @@ CONFIG_SCSI_SPI_ATTRS=y # CONFIG_SCSI_AIC7XXX_OLD is not set # CONFIG_SCSI_AIC79XX is not set # CONFIG_SCSI_AIC94XX is not set -# CONFIG_SCSI_DPT_I2O is not set # CONFIG_SCSI_ARCMSR is not set # CONFIG_MEGARAID_NEWGEN is not set # CONFIG_MEGARAID_LEGACY is not set @@ -389,14 +349,9 @@ CONFIG_SCSI_QLOGICPTI=m # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_NSP32 is not set # CONFIG_SCSI_DEBUG is not set -CONFIG_SCSI_ESP_CORE=y CONFIG_SCSI_SUNESP=y # CONFIG_SCSI_SRP is not set # CONFIG_ATA is not set - -# -# Multi-device support (RAID and LVM) -# # CONFIG_MD is not set # @@ -412,30 +367,16 @@ CONFIG_SCSI_SUNESP=y # # CONFIG_FIREWIRE is not set # CONFIG_IEEE1394 is not set - -# -# I2O device support -# # CONFIG_I2O is not set - -# -# Network device support -# CONFIG_NETDEVICES=y +# CONFIG_NETDEVICES_MULTIQUEUE is not set CONFIG_DUMMY=m # CONFIG_BONDING is not set +# CONFIG_MACVLAN is not set # CONFIG_EQUALIZER is not set CONFIG_TUN=m - -# -# ARCnet devices -# # CONFIG_ARCNET is not set # CONFIG_PHYLIB is not set - -# -# Ethernet (10 or 100Mbit) -# CONFIG_NET_ETHERNET=y CONFIG_MII=m CONFIG_SUNLANCE=y @@ -445,10 +386,6 @@ CONFIG_SUNQE=m # CONFIG_SUNGEM is not set # CONFIG_CASSINI is not set # CONFIG_NET_VENDOR_3COM is not set - -# -# Tulip family network device support -# # CONFIG_NET_TULIP is not set # CONFIG_HP100 is not set # CONFIG_NET_PCI is not set @@ -464,7 +401,7 @@ CONFIG_NETDEV_1000=y # CONFIG_SIS190 is not set # CONFIG_SKGE is not set # CONFIG_SKY2 is not set -# CONFIG_SK98LIN is not set +# CONFIG_VIA_VELOCITY is not set # CONFIG_TIGON3 is not set # CONFIG_BNX2 is not set # CONFIG_QLA3XXX is not set @@ -477,11 +414,6 @@ CONFIG_NETDEV_10000=y # CONFIG_MYRI10GE is not set # CONFIG_NETXEN_NIC is not set # CONFIG_MLX4_CORE is not set -CONFIG_MLX4_DEBUG=y - -# -# Token Ring devices -# # CONFIG_TR is not set # @@ -499,15 +431,7 @@ CONFIG_MLX4_DEBUG=y # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set - -# -# ISDN subsystem -# # CONFIG_ISDN is not set - -# -# Telephony Support -# # CONFIG_PHONE is not set # @@ -515,6 +439,7 @@ CONFIG_MLX4_DEBUG=y # CONFIG_INPUT=y # CONFIG_INPUT_FF_MEMLESS is not set +# CONFIG_INPUT_POLLDEV is not set # # Userland interfaces @@ -593,22 +518,13 @@ CONFIG_SERIAL_CORE_CONSOLE=y CONFIG_UNIX98_PTYS=y CONFIG_LEGACY_PTYS=y CONFIG_LEGACY_PTY_COUNT=256 - -# -# IPMI -# # CONFIG_IPMI_HANDLER is not set # CONFIG_WATCHDOG is not set CONFIG_HW_RANDOM=m CONFIG_JS_RTC=m # CONFIG_R3964 is not set # CONFIG_APPLICOM is not set -# CONFIG_DRM is not set # CONFIG_RAW_DRIVER is not set - -# -# TPM devices -# # CONFIG_TCG_TPM is not set CONFIG_DEVPORT=y # CONFIG_I2C is not set @@ -618,20 +534,24 @@ CONFIG_DEVPORT=y # # CONFIG_SPI is not set # CONFIG_SPI_MASTER is not set - -# -# Dallas's 1-wire bus -# # CONFIG_W1 is not set +# CONFIG_POWER_SUPPLY is not set CONFIG_HWMON=y # CONFIG_HWMON_VID is not set # CONFIG_SENSORS_ABITUGURU is not set +# CONFIG_SENSORS_ABITUGURU3 is not set # CONFIG_SENSORS_F71805F is not set +# CONFIG_SENSORS_IT87 is not set +# CONFIG_SENSORS_PC87360 is not set # CONFIG_SENSORS_PC87427 is not set +# CONFIG_SENSORS_SIS5595 is not set # CONFIG_SENSORS_SMSC47M1 is not set # CONFIG_SENSORS_SMSC47B397 is not set +# CONFIG_SENSORS_VIA686A is not set # CONFIG_SENSORS_VT1211 is not set +# CONFIG_SENSORS_VT8231 is not set # CONFIG_SENSORS_W83627HF is not set +# CONFIG_SENSORS_W83627EHF is not set # CONFIG_HWMON_DEBUG_CHIP is not set # @@ -656,6 +576,7 @@ CONFIG_HWMON=y # # CONFIG_DISPLAY_SUPPORT is not set # CONFIG_VGASTATE is not set +# CONFIG_VIDEO_OUTPUT_CONTROL is not set # CONFIG_FB is not set # @@ -668,16 +589,10 @@ CONFIG_DUMMY_CONSOLE=y # Sound # # CONFIG_SOUND is not set - -# -# HID Devices -# +CONFIG_HID_SUPPORT=y CONFIG_HID=y # CONFIG_HID_DEBUG is not set - -# -# USB support -# +CONFIG_USB_SUPPORT=y CONFIG_USB_ARCH_HAS_HCD=y CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB_ARCH_HAS_EHCI=y @@ -692,29 +607,9 @@ CONFIG_USB_ARCH_HAS_EHCI=y # # CONFIG_USB_GADGET is not set # CONFIG_MMC is not set - -# -# LED devices -# # CONFIG_NEW_LEDS is not set - -# -# LED drivers -# - -# -# LED Triggers -# - -# -# InfiniBand support -# # CONFIG_INFINIBAND is not set -# -# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) -# - # # Real Time Clock # @@ -733,6 +628,11 @@ CONFIG_USB_ARCH_HAS_EHCI=y # DMA Devices # +# +# Userspace I/O +# +# CONFIG_UIO is not set + # # Misc Linux/SPARC drivers # @@ -853,7 +753,6 @@ CONFIG_CIFS=m # CONFIG_CODA_FS is not set CONFIG_AFS_FS=m # CONFIG_AFS_DEBUG is not set -# CONFIG_9P_FS is not set # # Partition Types @@ -927,6 +826,7 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_HEADERS_CHECK is not set CONFIG_DEBUG_KERNEL=y CONFIG_DETECT_SOFTLOCKUP=y +# CONFIG_SCHED_DEBUG is not set # CONFIG_SCHEDSTATS is not set # CONFIG_TIMER_STATS is not set # CONFIG_DEBUG_SLAB is not set @@ -953,10 +853,6 @@ CONFIG_FORCED_INLINING=y CONFIG_KEYS=y # CONFIG_KEYS_DEBUG_PROC_KEYS is not set # CONFIG_SECURITY is not set - -# -# Cryptographic options -# CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=y CONFIG_CRYPTO_BLKCIPHER=y @@ -996,10 +892,7 @@ CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_CRC32C=m # CONFIG_CRYPTO_CAMELLIA is not set # CONFIG_CRYPTO_TEST is not set - -# -# Hardware crypto devices -# +# CONFIG_CRYPTO_HW is not set # # Library routines @@ -1009,6 +902,7 @@ CONFIG_BITREVERSE=y # CONFIG_CRC16 is not set # CONFIG_CRC_ITU_T is not set CONFIG_CRC32=y +# CONFIG_CRC7 is not set CONFIG_LIBCRC32C=m CONFIG_ZLIB_INFLATE=y CONFIG_ZLIB_DEFLATE=y -- cgit v1.2.3 From b84d879639f83d35d3fcd909222522c928bf974b Mon Sep 17 00:00:00 2001 From: Mark Fortescue Date: Wed, 25 Jul 2007 18:30:08 -0700 Subject: [PARTITION] MSDOS: Fix Sun num_partitions handling. Correct the Solaris x86 number of partitions (slices) is a way that is backward compatible with the earlier size. This works without a new VTOC structure definition as the timestamp and v_asciilabel fields in the VTOC are not used by the kernel yet. Signed-off-by: Mark Fortescue Signed-off-by: David S. Miller --- fs/partitions/msdos.c | 5 ++++- include/linux/genhd.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 4ccec4cd136..5567ec0d03a 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -203,6 +203,7 @@ parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, Sector sect; struct solaris_x86_vtoc *v; int i; + short max_nparts; v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, §); if (!v) @@ -218,7 +219,9 @@ parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, put_dev_sector(sect); return; } - for (i=0; inextlimit; i++) { + /* Ensure we can handle previous case of VTOC with 8 entries gracefully */ + max_nparts = le16_to_cpu (v->v_nparts) > 8 ? SOLARIS_X86_NUMSLICE : 8; + for (i=0; inextlimit; i++) { struct solaris_x86_slice *s = &v->v_slice[i]; if (s->s_size == 0) continue; diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 9756fc102a8..a47b8025d39 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -264,7 +264,7 @@ static inline void set_capacity(struct gendisk *disk, sector_t size) #ifdef CONFIG_SOLARIS_X86_PARTITION -#define SOLARIS_X86_NUMSLICE 8 +#define SOLARIS_X86_NUMSLICE 16 #define SOLARIS_X86_VTOC_SANE (0x600DDEEEUL) struct solaris_x86_slice { -- cgit v1.2.3 From a2d6ea0180531b5ace2dc1e64b6e22465ed51267 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 25 Jul 2007 23:30:16 -0700 Subject: [SPARC64]: Fix sun4u PCI config space accesses on sun4u. Don't provide fake PCI config space for sun4u. Also, put back the funny host controller space handling that at least Sabre needs. You have to read PCI host controller registers at their nature size otherwise you get zeros instead of correct values. Signed-off-by: David S. Miller --- arch/sparc64/kernel/pci.c | 15 +++-- arch/sparc64/kernel/pci_common.c | 123 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 126 insertions(+), 12 deletions(-) diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 55ad1b899bb..77449a00575 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -422,10 +422,15 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, dev->multifunction = 0; /* maybe a lie? */ if (host_controller) { - dev->vendor = 0x108e; - dev->device = 0x8000; - dev->subsystem_vendor = 0x0000; - dev->subsystem_device = 0x0000; + if (tlb_type != hypervisor) { + pci_read_config_word(dev, PCI_VENDOR_ID, + &dev->vendor); + pci_read_config_word(dev, PCI_DEVICE_ID, + &dev->device); + } else { + dev->vendor = PCI_VENDOR_ID_SUN; + dev->device = 0x80f0; + } dev->cfg_size = 256; dev->class = PCI_CLASS_BRIDGE_HOST << 8; sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), @@ -818,7 +823,7 @@ int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev, { static u8 fake_pci_config[] = { 0x8e, 0x10, /* Vendor: 0x108e (Sun) */ - 0x00, 0x80, /* Device: 0x8000 (PBM) */ + 0xf0, 0x80, /* Device: 0x80f0 (Fire) */ 0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */ 0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */ 0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */ diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 4249214608a..2f61c4b1259 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -44,6 +44,67 @@ static void *sun4u_config_mkaddr(struct pci_pbm_info *pbm, return (void *) (pbm->config_space | bus | devfn | reg); } +/* At least on Sabre, it is necessary to access all PCI host controller + * registers at their natural size, otherwise zeros are returned. + * Strange but true, and I see no language in the UltraSPARC-IIi + * programmer's manual that mentions this even indirectly. + */ +static int sun4u_read_pci_cfg_host(struct pci_pbm_info *pbm, + unsigned char bus, unsigned int devfn, + int where, int size, u32 *value) +{ + u32 tmp32, *addr; + u16 tmp16; + u8 tmp8; + + addr = sun4u_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + switch (size) { + case 1: + if (where < 8) { + unsigned long align = (unsigned long) addr; + + align &= ~1; + pci_config_read16((u16 *)align, &tmp16); + if (where & 1) + *value = tmp16 >> 8; + else + *value = tmp16 & 0xff; + } else { + pci_config_read8((u8 *)addr, &tmp8); + *value = (u32) tmp8; + } + break; + + case 2: + if (where < 8) { + pci_config_read16((u16 *)addr, &tmp16); + *value = (u32) tmp16; + } else { + pci_config_read8((u8 *)addr, &tmp8); + *value = (u32) tmp8; + pci_config_read8(((u8 *)addr) + 1, &tmp8); + *value |= ((u32) tmp8) << 8; + } + break; + + case 4: + tmp32 = 0xffffffff; + sun4u_read_pci_cfg_host(pbm, bus, devfn, + where, 2, &tmp32); + *value = tmp32; + + tmp32 = 0xffffffff; + sun4u_read_pci_cfg_host(pbm, bus, devfn, + where + 2, 2, &tmp32); + *value |= tmp32 << 16; + break; + } + return PCIBIOS_SUCCESSFUL; +} + static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, int where, int size, u32 *value) { @@ -53,10 +114,6 @@ static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, u16 tmp16; u8 tmp8; - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_read_pci_cfg(bus_dev, devfn, where, - size, value); - switch (size) { case 1: *value = 0xff; @@ -69,6 +126,10 @@ static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, break; } + if (!bus_dev->number && !PCI_SLOT(devfn)) + return sun4u_read_pci_cfg_host(pbm, bus, devfn, where, + size, value); + addr = sun4u_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; @@ -101,6 +162,53 @@ static int sun4u_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, return PCIBIOS_SUCCESSFUL; } +static int sun4u_write_pci_cfg_host(struct pci_pbm_info *pbm, + unsigned char bus, unsigned int devfn, + int where, int size, u32 value) +{ + u32 *addr; + + addr = sun4u_config_mkaddr(pbm, bus, devfn, where); + if (!addr) + return PCIBIOS_SUCCESSFUL; + + switch (size) { + case 1: + if (where < 8) { + unsigned long align = (unsigned long) addr; + u16 tmp16; + + align &= ~1; + pci_config_read16((u16 *)align, &tmp16); + if (where & 1) { + tmp16 &= 0x00ff; + tmp16 |= value << 8; + } else { + tmp16 &= 0xff00; + tmp16 |= value; + } + pci_config_write16((u16 *)align, tmp16); + } else + pci_config_write8((u8 *)addr, value); + break; + case 2: + if (where < 8) { + pci_config_write16((u16 *)addr, value); + } else { + pci_config_write8((u8 *)addr, value & 0xff); + pci_config_write8(((u8 *)addr) + 1, value >> 8); + } + break; + case 4: + sun4u_write_pci_cfg_host(pbm, bus, devfn, + where, 2, value & 0xffff); + sun4u_write_pci_cfg_host(pbm, bus, devfn, + where + 2, 2, value >> 16); + break; + } + return PCIBIOS_SUCCESSFUL; +} + static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, int where, int size, u32 value) { @@ -108,9 +216,10 @@ static int sun4u_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, unsigned char bus = bus_dev->number; u32 *addr; - if (bus_dev == pbm->pci_bus && devfn == 0x00) - return pci_host_bridge_write_pci_cfg(bus_dev, devfn, where, - size, value); + if (!bus_dev->number && !PCI_SLOT(devfn)) + return sun4u_write_pci_cfg_host(pbm, bus, devfn, where, + size, value); + addr = sun4u_config_mkaddr(pbm, bus, devfn, where); if (!addr) return PCIBIOS_SUCCESSFUL; -- cgit v1.2.3 From b65f0755fd08c92f377fb434076865284283e2c1 Mon Sep 17 00:00:00 2001 From: Mark Fortescue Date: Wed, 25 Jul 2007 23:45:10 -0700 Subject: [SPARC]: Fix floppy on some sun4c systems. Add in code to support an 82077 FDC on sun4c systems. There is a problem with spurious interrupts but it does apear to work. Testing on my SS2 (82072A FDC) shows that the floppy driver is not 100% with sun4c any way (any spurious interrupt kills it, requiring a reboot to recover). Signed-off-by: Mark Fortescue Signed-off-by: David S. Miller --- include/asm-sparc/floppy.h | 80 +++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 30 deletions(-) diff --git a/include/asm-sparc/floppy.h b/include/asm-sparc/floppy.h index 9073c84218c..28ce2b9c3da 100644 --- a/include/asm-sparc/floppy.h +++ b/include/asm-sparc/floppy.h @@ -101,6 +101,29 @@ static struct sun_floppy_ops sun_fdops; #define CROSS_64KB(a,s) (0) /* Routines unique to each controller type on a Sun. */ +static void sun_set_dor(unsigned char value, int fdc_82077) +{ + if (sparc_cpu_model == sun4c) { + unsigned int bits = 0; + if (value & 0x10) + bits |= AUXIO_FLPY_DSEL; + if ((value & 0x80) == 0) + bits |= AUXIO_FLPY_EJCT; + set_auxio(bits, (~bits) & (AUXIO_FLPY_DSEL|AUXIO_FLPY_EJCT)); + } + if (fdc_82077) { + sun_fdc->dor_82077 = value; + } +} + +static unsigned char sun_read_dir(void) +{ + if (sparc_cpu_model == sun4c) + return (get_auxio() & AUXIO_FLPY_DCHG) ? 0x80 : 0; + else + return sun_fdc->dir_82077; +} + static unsigned char sun_82072_fd_inb(int port) { udelay(5); @@ -113,7 +136,7 @@ static unsigned char sun_82072_fd_inb(int port) case 5: /* FD_DATA */ return sun_fdc->data_82072; case 7: /* FD_DIR */ - return (get_auxio() & AUXIO_FLPY_DCHG)? 0x80: 0; + return sun_read_dir(); }; panic("sun_82072_fd_inb: How did I get here?"); } @@ -126,20 +149,7 @@ static void sun_82072_fd_outb(unsigned char value, int port) printk("floppy: Asked to write to unknown port %d\n", port); panic("floppy: Port bolixed."); case 2: /* FD_DOR */ - /* Oh geese, 82072 on the Sun has no DOR register, - * the functionality is implemented via the AUXIO - * I/O register. So we must emulate the behavior. - * - * ASSUMPTIONS: There will only ever be one floppy - * drive attached to a Sun controller - * and it will be at drive zero. - */ - { - unsigned bits = 0; - if (value & 0x10) bits |= AUXIO_FLPY_DSEL; - if ((value & 0x80) == 0) bits |= AUXIO_FLPY_EJCT; - set_auxio(bits, (~bits) & (AUXIO_FLPY_DSEL|AUXIO_FLPY_EJCT)); - } + sun_set_dor(value, 0); break; case 5: /* FD_DATA */ sun_fdc->data_82072 = value; @@ -161,15 +171,22 @@ static unsigned char sun_82077_fd_inb(int port) default: printk("floppy: Asked to read unknown port %d\n", port); panic("floppy: Port bolixed."); + case 0: /* FD_STATUS_0 */ + return sun_fdc->status1_82077; + case 1: /* FD_STATUS_1 */ + return sun_fdc->status2_82077; + case 2: /* FD_DOR */ + return sun_fdc->dor_82077; + case 3: /* FD_TDR */ + return sun_fdc->tapectl_82077; case 4: /* FD_STATUS */ return sun_fdc->status_82077 & ~STATUS_DMA; case 5: /* FD_DATA */ return sun_fdc->data_82077; case 7: /* FD_DIR */ - /* XXX: Is DCL on 0x80 in sun4m? */ - return sun_fdc->dir_82077; + return sun_read_dir(); }; - panic("sun_82072_fd_inb: How did I get here?"); + panic("sun_82077_fd_inb: How did I get here?"); } static void sun_82077_fd_outb(unsigned char value, int port) @@ -180,8 +197,7 @@ static void sun_82077_fd_outb(unsigned char value, int port) printk("floppy: Asked to write to unknown port %d\n", port); panic("floppy: Port bolixed."); case 2: /* FD_DOR */ - /* Happily, the 82077 has a real DOR register. */ - sun_fdc->dor_82077 = value; + sun_set_dor(value, 1); break; case 5: /* FD_DATA */ sun_fdc->data_82077 = value; @@ -192,6 +208,9 @@ static void sun_82077_fd_outb(unsigned char value, int port) case 4: /* FD_STATUS */ sun_fdc->status_82077 = value; break; + case 3: /* FD_TDR */ + sun_fdc->tapectl_82077 = value; + break; }; return; } @@ -332,16 +351,17 @@ static int sun_floppy_init(void) goto no_sun_fdc; } - if(sparc_cpu_model == sun4c) { - sun_fdops.fd_inb = sun_82072_fd_inb; - sun_fdops.fd_outb = sun_82072_fd_outb; - fdc_status = &sun_fdc->status_82072; - /* printk("AUXIO @0x%lx\n", auxio_register); */ /* P3 */ - } else { - sun_fdops.fd_inb = sun_82077_fd_inb; - sun_fdops.fd_outb = sun_82077_fd_outb; - fdc_status = &sun_fdc->status_82077; - /* printk("DOR @0x%p\n", &sun_fdc->dor_82077); */ /* P3 */ + sun_fdops.fd_inb = sun_82077_fd_inb; + sun_fdops.fd_outb = sun_82077_fd_outb; + fdc_status = &sun_fdc->status_82077; + + if (sun_fdc->dor_82077 == 0x80) { + sun_fdc->dor_82077 = 0x02; + if (sun_fdc->dor_82077 == 0x80) { + sun_fdops.fd_inb = sun_82072_fd_inb; + sun_fdops.fd_outb = sun_82072_fd_outb; + fdc_status = &sun_fdc->status_82072; + } } /* Success... */ -- cgit v1.2.3 From 3961bae0ac030a70ae2e0578270203889021f1a1 Mon Sep 17 00:00:00 2001 From: Mark Fortescue Date: Thu, 26 Jul 2007 00:17:22 -0700 Subject: [PARTITION]: Sun/Solaris VTOC table corrections Start doing VTOC validation before using its contents. The validation is adjusted so as not to break existing setups that do not set the VTOC version, sanity and partition count entries. VTOC tables with more than 8 partitions will NOT be used. Signed-off-by: Mark Fortescue Signed-off-by: David S. Miller --- fs/partitions/sun.c | 62 ++++++++++++++++++++++++++++++++++++++--------------- fs/partitions/sun.h | 1 + 2 files changed, 46 insertions(+), 17 deletions(-) diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c index 123f8b46c8b..794118da4ef 100644 --- a/fs/partitions/sun.c +++ b/fs/partitions/sun.c @@ -19,34 +19,47 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev) Sector sect; struct sun_disklabel { unsigned char info[128]; /* Informative text string */ - unsigned char spare0[14]; - struct sun_info { - unsigned char spare1; - unsigned char id; - unsigned char spare2; - unsigned char flags; - } infos[8]; - unsigned char spare[246]; /* Boot information etc. */ + struct sun_vtoc { + __be32 version; /* Layout version */ + char volume[8]; /* Volume name */ + __be16 nparts; /* Number of partitions */ + struct sun_info { /* Partition hdrs, sec 2 */ + __be16 id; + __be16 flags; + } infos[8]; + __be16 padding; /* Alignment padding */ + __be32 bootinfo[3]; /* Info needed by mboot */ + __be32 sanity; /* To verify vtoc sanity */ + __be32 reserved[10]; /* Free space */ + __be32 timestamp[8]; /* Partition timestamp */ + } vtoc; + __be32 write_reinstruct; /* sectors to skip, writes */ + __be32 read_reinstruct; /* sectors to skip, reads */ + unsigned char spare[148]; /* Padding */ __be16 rspeed; /* Disk rotational speed */ __be16 pcylcount; /* Physical cylinder count */ __be16 sparecyl; /* extra sects per cylinder */ - unsigned char spare2[4]; /* More magic... */ + __be16 obs1; /* gap1 */ + __be16 obs2; /* gap2 */ __be16 ilfact; /* Interleave factor */ __be16 ncyl; /* Data cylinder count */ __be16 nacyl; /* Alt. cylinder count */ __be16 ntrks; /* Tracks per cylinder */ __be16 nsect; /* Sectors per track */ - unsigned char spare3[4]; /* Even more magic... */ + __be16 obs3; /* bhead - Label head offset */ + __be16 obs4; /* ppart - Physical Partition */ struct sun_partition { __be32 start_cylinder; __be32 num_sectors; } partitions[8]; __be16 magic; /* Magic number */ __be16 csum; /* Label xor'd checksum */ - } * label; + } * label; struct sun_partition *p; unsigned long spc; char b[BDEVNAME_SIZE]; + int use_vtoc; + int nparts; label = (struct sun_disklabel *)read_dev_sector(bdev, 0, §); if (!label) @@ -70,9 +83,22 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev) return 0; } - /* All Sun disks have 8 partition entries */ + /* Check to see if we can use the VTOC table */ + use_vtoc = ((be32_to_cpu(label->vtoc.sanity) == SUN_VTOC_SANITY) && + (be32_to_cpu(label->vtoc.version) == 1) && + (be16_to_cpu(label->vtoc.nparts) <= 8)); + + /* Use 8 partition entries if not specified in validated VTOC */ + nparts = (use_vtoc) ? be16_to_cpu(label->vtoc.nparts) : 8; + + /* + * So that old Linux-Sun partitions continue to work, + * alow the VTOC to be used under the additional condition ... + */ + use_vtoc = use_vtoc || !(label->vtoc.sanity | + label->vtoc.version | label->vtoc.nparts); spc = be16_to_cpu(label->ntrks) * be16_to_cpu(label->nsect); - for (i = 0; i < 8; i++, p++) { + for (i = 0; i < nparts; i++, p++) { unsigned long st_sector; unsigned int num_sectors; @@ -81,10 +107,12 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev) if (num_sectors) { put_partition(state, slot, st_sector, num_sectors); state->parts[slot].flags = 0; - if (label->infos[i].id == LINUX_RAID_PARTITION) - state->parts[slot].flags |= ADDPART_FLAG_RAID; - if (label->infos[i].id == SUN_WHOLE_DISK) - state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK; + if (use_vtoc) { + if (be16_to_cpu(label->vtoc.infos[i].id) == LINUX_RAID_PARTITION) + state->parts[slot].flags |= ADDPART_FLAG_RAID; + else if (be16_to_cpu(label->vtoc.infos[i].id) == SUN_WHOLE_DISK) + state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK; + } } slot++; } diff --git a/fs/partitions/sun.h b/fs/partitions/sun.h index b1b19fda7b2..7f864d1f86d 100644 --- a/fs/partitions/sun.h +++ b/fs/partitions/sun.h @@ -3,5 +3,6 @@ */ #define SUN_LABEL_MAGIC 0xDABE +#define SUN_VTOC_SANITY 0x600DDEEE int sun_partition(struct parsed_partitions *state, struct block_device *bdev); -- cgit v1.2.3 From a0afaa6ab12cf696d170c22a8fdfd88c3e33555c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 27 Jul 2007 14:40:27 -0700 Subject: [SPARC64]: Handle mostek clock type in mini_rtc driver. Now that drivers/sbus/char/rtc.c is sparc32 only, we need this. Signed-off-by: David S. Miller --- arch/sparc64/kernel/time.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 49063ca2efc..69cad1b653c 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1460,6 +1460,74 @@ static int cmos_set_rtc_time(struct rtc_time *rtc_tm) } #endif /* CONFIG_PCI */ +static void mostek_get_rtc_time(struct rtc_time *rtc_tm) +{ + void __iomem *regs = mstk48t02_regs; + u8 tmp; + + spin_lock_irq(&mostek_lock); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_READ; + mostek_write(regs + MOSTEK_CREG, tmp); + + rtc_tm->tm_sec = MSTK_REG_SEC(regs); + rtc_tm->tm_min = MSTK_REG_MIN(regs); + rtc_tm->tm_hour = MSTK_REG_HOUR(regs); + rtc_tm->tm_mday = MSTK_REG_DOM(regs); + rtc_tm->tm_mon = MSTK_REG_MONTH(regs); + rtc_tm->tm_year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) ); + rtc_tm->tm_wday = MSTK_REG_DOW(regs); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_READ; + mostek_write(regs + MOSTEK_CREG, tmp); + + spin_unlock_irq(&mostek_lock); + + rtc_tm->tm_mon--; + rtc_tm->tm_wday--; + rtc_tm->tm_year -= 1900; +} + +static int mostek_set_rtc_time(struct rtc_time *rtc_tm) +{ + unsigned char mon, day, hrs, min, sec, wday; + void __iomem *regs = mstk48t02_regs; + unsigned int yrs; + u8 tmp; + + yrs = rtc_tm->tm_year + 1900; + mon = rtc_tm->tm_mon + 1; + day = rtc_tm->tm_mday; + wday = rtc_tm->tm_wday + 1; + hrs = rtc_tm->tm_hour; + min = rtc_tm->tm_min; + sec = rtc_tm->tm_sec; + + spin_lock_irq(&mostek_lock); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp |= MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + + MSTK_SET_REG_SEC(regs, sec); + MSTK_SET_REG_MIN(regs, min); + MSTK_SET_REG_HOUR(regs, hrs); + MSTK_SET_REG_DOW(regs, wday); + MSTK_SET_REG_DOM(regs, day); + MSTK_SET_REG_MONTH(regs, mon); + MSTK_SET_REG_YEAR(regs, yrs - MSTK_YEAR_ZERO); + + tmp = mostek_read(regs + MOSTEK_CREG); + tmp &= ~MSTK_CREG_WRITE; + mostek_write(regs + MOSTEK_CREG, tmp); + + spin_unlock_irq(&mostek_lock); + + return 0; +} + struct mini_rtc_ops { void (*get_rtc_time)(struct rtc_time *); int (*set_rtc_time)(struct rtc_time *); @@ -1487,6 +1555,11 @@ static struct mini_rtc_ops cmos_rtc_ops = { }; #endif /* CONFIG_PCI */ +static struct mini_rtc_ops mostek_rtc_ops = { + .get_rtc_time = mostek_get_rtc_time, + .set_rtc_time = mostek_set_rtc_time, +}; + static struct mini_rtc_ops *mini_rtc_ops; static inline void mini_get_rtc_time(struct rtc_time *time) @@ -1615,6 +1688,8 @@ static int __init rtc_mini_init(void) else if (ds1287_regs) mini_rtc_ops = &cmos_rtc_ops; #endif /* CONFIG_PCI */ + else if (mstk48t02_regs) + mini_rtc_ops = &mostek_rtc_ops; else return -ENODEV; -- cgit v1.2.3 From c7f439b99efbea74c70a5531f92566db5a6731f2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 27 Jul 2007 22:31:46 -0700 Subject: [VIDEO]: Fix OOPS in all SBUS framebuffer drivers. All of these drivers use a silly: struct all_info { struct fb_info info; struct foo_par par; }; struct all_info *all = kzalloc(sizeof(*all), GFP_KERNEL); all->info.par = &all->par; etc. etc. code sequence, basically replicating the provided framebuffer_alloc()/framebuffer_release(), and doing it badly. Not only is this massive code duplication, it also caused a bug in that we weren't setting the fb_info->device pointer which results in an OOPS when fb_is_primary_device() runs. Fix all of this by using framebuffer_{alloc,release}() and passing in "&of_device->dev" as the device pointer. Signed-off-by: David S. Miller --- drivers/video/bw2.c | 105 ++++++++++++++-------------- drivers/video/cg14.c | 150 ++++++++++++++++++++-------------------- drivers/video/cg3.c | 136 ++++++++++++++++++------------------- drivers/video/cg6.c | 161 ++++++++++++++++++++----------------------- drivers/video/ffb.c | 170 ++++++++++++++++++++++------------------------ drivers/video/leo.c | 147 +++++++++++++++++++--------------------- drivers/video/p9100.c | 138 +++++++++++++++++-------------------- drivers/video/tcx.c | 184 ++++++++++++++++++++++++-------------------------- 8 files changed, 567 insertions(+), 624 deletions(-) diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index b0b2e40bbd9..718b9f83736 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c @@ -279,90 +279,91 @@ static void __devinit bw2_do_default_mode(struct bw2_par *par, } } -struct all_info { - struct fb_info info; - struct bw2_par par; -}; - -static int __devinit bw2_init_one(struct of_device *op) +static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match) { struct device_node *dp = op->node; - struct all_info *all; + struct fb_info *info; + struct bw2_par *par; int linebytes, err; - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + info = framebuffer_alloc(sizeof(struct bw2_par), &op->dev); - spin_lock_init(&all->par.lock); + err = -ENOMEM; + if (!info) + goto out_err; + par = info->par; - all->par.physbase = op->resource[0].start; - all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; + spin_lock_init(&par->lock); - sbusfb_fill_var(&all->info.var, dp->node, 1); + par->physbase = op->resource[0].start; + par->which_io = op->resource[0].flags & IORESOURCE_BITS; + + sbusfb_fill_var(&info->var, dp->node, 1); linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); + info->var.xres); - all->info.var.red.length = all->info.var.green.length = - all->info.var.blue.length = all->info.var.bits_per_pixel; - all->info.var.red.offset = all->info.var.green.offset = - all->info.var.blue.offset = 0; + info->var.red.length = info->var.green.length = + info->var.blue.length = info->var.bits_per_pixel; + info->var.red.offset = info->var.green.offset = + info->var.blue.offset = 0; - all->par.regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET, - sizeof(struct bw2_regs), "bw2 regs"); + par->regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET, + sizeof(struct bw2_regs), "bw2 regs"); + if (!par->regs) + goto out_release_fb; if (!of_find_property(dp, "width", NULL)) - bw2_do_default_mode(&all->par, &all->info, &linebytes); + bw2_do_default_mode(par, info, &linebytes); - all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); - all->info.flags = FBINFO_DEFAULT; - all->info.fbops = &bw2_ops; + info->flags = FBINFO_DEFAULT; + info->fbops = &bw2_ops; - all->info.screen_base = - of_ioremap(&op->resource[0], 0, all->par.fbsize, "bw2 ram"); - all->info.par = &all->par; + info->screen_base = of_ioremap(&op->resource[0], 0, + par->fbsize, "bw2 ram"); + if (!info->screen_base) + goto out_unmap_regs; - bw2_blank(0, &all->info); + bw2_blank(0, info); - bw2_init_fix(&all->info, linebytes); + bw2_init_fix(info, linebytes); - err= register_framebuffer(&all->info); - if (err < 0) { - of_iounmap(&op->resource[0], - all->par.regs, sizeof(struct bw2_regs)); - of_iounmap(&op->resource[0], - all->info.screen_base, all->par.fbsize); - kfree(all); - return err; - } + err = register_framebuffer(info); + if (err < 0) + goto out_unmap_screen; - dev_set_drvdata(&op->dev, all); + dev_set_drvdata(&op->dev, info); printk("%s: bwtwo at %lx:%lx\n", - dp->full_name, - all->par.which_io, all->par.physbase); + dp->full_name, par->which_io, par->physbase); return 0; -} -static int __devinit bw2_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct of_device *op = to_of_device(&dev->dev); +out_unmap_screen: + of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + +out_unmap_regs: + of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); + +out_release_fb: + framebuffer_release(info); - return bw2_init_one(op); +out_err: + return err; } static int __devexit bw2_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&op->dev); + struct fb_info *info = dev_get_drvdata(&op->dev); + struct bw2_par *par = info->par; - unregister_framebuffer(&all->info); + unregister_framebuffer(info); - of_iounmap(&op->resource[0], all->par.regs, sizeof(struct bw2_regs)); - of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); + of_iounmap(&op->resource[0], info->screen_base, par->fbsize); - kfree(all); + framebuffer_release(info); dev_set_drvdata(&op->dev, NULL); diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index b071bb632b9..41f6dbf61be 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c @@ -448,81 +448,79 @@ static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __devinitdata = { { .size = 0 } }; -struct all_info { - struct fb_info info; - struct cg14_par par; -}; - -static void cg14_unmap_regs(struct of_device *op, struct all_info *all) +static void cg14_unmap_regs(struct of_device *op, struct fb_info *info, + struct cg14_par *par) { - if (all->par.regs) + if (par->regs) of_iounmap(&op->resource[0], - all->par.regs, sizeof(struct cg14_regs)); - if (all->par.clut) + par->regs, sizeof(struct cg14_regs)); + if (par->clut) of_iounmap(&op->resource[0], - all->par.clut, sizeof(struct cg14_clut)); - if (all->par.cursor) + par->clut, sizeof(struct cg14_clut)); + if (par->cursor) of_iounmap(&op->resource[0], - all->par.cursor, sizeof(struct cg14_cursor)); - if (all->info.screen_base) + par->cursor, sizeof(struct cg14_cursor)); + if (info->screen_base) of_iounmap(&op->resource[1], - all->info.screen_base, all->par.fbsize); + info->screen_base, par->fbsize); } -static int __devinit cg14_init_one(struct of_device *op) +static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match) { struct device_node *dp = op->node; - struct all_info *all; + struct fb_info *info; + struct cg14_par *par; int is_8mb, linebytes, i, err; - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + info = framebuffer_alloc(sizeof(struct cg14_par), &op->dev); + + err = -ENOMEM; + if (!info) + goto out_err; + par = info->par; - spin_lock_init(&all->par.lock); + spin_lock_init(&par->lock); - sbusfb_fill_var(&all->info.var, dp->node, 8); - all->info.var.red.length = 8; - all->info.var.green.length = 8; - all->info.var.blue.length = 8; + sbusfb_fill_var(&info->var, dp->node, 8); + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); - all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + info->var.xres); + par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); if (!strcmp(dp->parent->name, "sbus") || !strcmp(dp->parent->name, "sbi")) { - all->par.physbase = op->resource[0].start; - all->par.iospace = op->resource[0].flags & IORESOURCE_BITS; + par->physbase = op->resource[0].start; + par->iospace = op->resource[0].flags & IORESOURCE_BITS; } else { - all->par.physbase = op->resource[1].start; - all->par.iospace = op->resource[0].flags & IORESOURCE_BITS; + par->physbase = op->resource[1].start; + par->iospace = op->resource[0].flags & IORESOURCE_BITS; } - all->par.regs = of_ioremap(&op->resource[0], 0, - sizeof(struct cg14_regs), "cg14 regs"); - all->par.clut = of_ioremap(&op->resource[0], CG14_CLUT1, - sizeof(struct cg14_clut), "cg14 clut"); - all->par.cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS, - sizeof(struct cg14_cursor), "cg14 cursor"); + par->regs = of_ioremap(&op->resource[0], 0, + sizeof(struct cg14_regs), "cg14 regs"); + par->clut = of_ioremap(&op->resource[0], CG14_CLUT1, + sizeof(struct cg14_clut), "cg14 clut"); + par->cursor = of_ioremap(&op->resource[0], CG14_CURSORREGS, + sizeof(struct cg14_cursor), "cg14 cursor"); - all->info.screen_base = of_ioremap(&op->resource[1], 0, - all->par.fbsize, "cg14 ram"); + info->screen_base = of_ioremap(&op->resource[1], 0, + par->fbsize, "cg14 ram"); - if (!all->par.regs || !all->par.clut || !all->par.cursor || - !all->info.screen_base) - cg14_unmap_regs(op, all); + if (!par->regs || !par->clut || !par->cursor || !info->screen_base) + goto out_unmap_regs; is_8mb = (((op->resource[1].end - op->resource[1].start) + 1) == (8 * 1024 * 1024)); - BUILD_BUG_ON(sizeof(all->par.mmap_map) != sizeof(__cg14_mmap_map)); + BUILD_BUG_ON(sizeof(par->mmap_map) != sizeof(__cg14_mmap_map)); - memcpy(&all->par.mmap_map, &__cg14_mmap_map, - sizeof(all->par.mmap_map)); + memcpy(&par->mmap_map, &__cg14_mmap_map, sizeof(par->mmap_map)); for (i = 0; i < CG14_MMAP_ENTRIES; i++) { - struct sbus_mmap_map *map = &all->par.mmap_map[i]; + struct sbus_mmap_map *map = &par->mmap_map[i]; if (!map->size) break; @@ -536,59 +534,55 @@ static int __devinit cg14_init_one(struct of_device *op) map->size *= 2; } - all->par.mode = MDI_8_PIX; - all->par.ramsize = (is_8mb ? 0x800000 : 0x400000); + par->mode = MDI_8_PIX; + par->ramsize = (is_8mb ? 0x800000 : 0x400000); - all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; - all->info.fbops = &cg14_ops; - all->info.par = &all->par; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + info->fbops = &cg14_ops; - __cg14_reset(&all->par); + __cg14_reset(par); - if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - cg14_unmap_regs(op, all); - kfree(all); - return -ENOMEM; - } - fb_set_cmap(&all->info.cmap, &all->info); + if (fb_alloc_cmap(&info->cmap, 256, 0)) + goto out_unmap_regs; - cg14_init_fix(&all->info, linebytes, dp); + fb_set_cmap(&info->cmap, info); - err = register_framebuffer(&all->info); - if (err < 0) { - fb_dealloc_cmap(&all->info.cmap); - cg14_unmap_regs(op, all); - kfree(all); - return err; - } + cg14_init_fix(info, linebytes, dp); + + err = register_framebuffer(info); + if (err < 0) + goto out_dealloc_cmap; - dev_set_drvdata(&op->dev, all); + dev_set_drvdata(&op->dev, info); printk("%s: cgfourteen at %lx:%lx, %dMB\n", dp->full_name, - all->par.iospace, all->par.physbase, - all->par.ramsize >> 20); + par->iospace, par->physbase, + par->ramsize >> 20); return 0; -} -static int __devinit cg14_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct of_device *op = to_of_device(&dev->dev); +out_dealloc_cmap: + fb_dealloc_cmap(&info->cmap); + +out_unmap_regs: + cg14_unmap_regs(op, info, par); - return cg14_init_one(op); +out_err: + return err; } static int __devexit cg14_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&op->dev); + struct fb_info *info = dev_get_drvdata(&op->dev); + struct cg14_par *par = info->par; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); - cg14_unmap_regs(op, all); + cg14_unmap_regs(op, info, par); - kfree(all); + framebuffer_release(info); dev_set_drvdata(&op->dev, NULL); diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index f042428a84f..5741b46ade1 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c @@ -353,104 +353,102 @@ static void __devinit cg3_do_default_mode(struct cg3_par *par) } } -struct all_info { - struct fb_info info; - struct cg3_par par; -}; - -static int __devinit cg3_init_one(struct of_device *op) +static int __devinit cg3_probe(struct of_device *op, + const struct of_device_id *match) { struct device_node *dp = op->node; - struct all_info *all; + struct fb_info *info; + struct cg3_par *par; int linebytes, err; - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + info = framebuffer_alloc(sizeof(struct cg3_par), &op->dev); - spin_lock_init(&all->par.lock); + err = -ENOMEM; + if (!info) + goto out_err; + par = info->par; - all->par.physbase = op->resource[0].start; - all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; + spin_lock_init(&par->lock); - sbusfb_fill_var(&all->info.var, dp->node, 8); - all->info.var.red.length = 8; - all->info.var.green.length = 8; - all->info.var.blue.length = 8; + par->physbase = op->resource[0].start; + par->which_io = op->resource[0].flags & IORESOURCE_BITS; + + sbusfb_fill_var(&info->var, dp->node, 8); + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; if (!strcmp(dp->name, "cgRDI")) - all->par.flags |= CG3_FLAG_RDI; - if (all->par.flags & CG3_FLAG_RDI) - cg3_rdi_maybe_fixup_var(&all->info.var, dp); + par->flags |= CG3_FLAG_RDI; + if (par->flags & CG3_FLAG_RDI) + cg3_rdi_maybe_fixup_var(&info->var, dp); linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); - all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + info->var.xres); + par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); - all->par.regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET, - sizeof(struct cg3_regs), "cg3 regs"); + par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET, + sizeof(struct cg3_regs), "cg3 regs"); + if (!par->regs) + goto out_release_fb; - all->info.flags = FBINFO_DEFAULT; - all->info.fbops = &cg3_ops; - all->info.screen_base = - of_ioremap(&op->resource[0], CG3_RAM_OFFSET, - all->par.fbsize, "cg3 ram"); - all->info.par = &all->par; + info->flags = FBINFO_DEFAULT; + info->fbops = &cg3_ops; + info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET, + par->fbsize, "cg3 ram"); + if (!info->screen_base) + goto out_unmap_regs; - cg3_blank(0, &all->info); + cg3_blank(0, info); if (!of_find_property(dp, "width", NULL)) - cg3_do_default_mode(&all->par); - - if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - of_iounmap(&op->resource[0], - all->par.regs, sizeof(struct cg3_regs)); - of_iounmap(&op->resource[0], - all->info.screen_base, all->par.fbsize); - kfree(all); - return -ENOMEM; - } - fb_set_cmap(&all->info.cmap, &all->info); - - cg3_init_fix(&all->info, linebytes, dp); - - err = register_framebuffer(&all->info); - if (err < 0) { - fb_dealloc_cmap(&all->info.cmap); - of_iounmap(&op->resource[0], - all->par.regs, sizeof(struct cg3_regs)); - of_iounmap(&op->resource[0], - all->info.screen_base, all->par.fbsize); - kfree(all); - return err; - } + cg3_do_default_mode(par); + + if (fb_alloc_cmap(&info->cmap, 256, 0)) + goto out_unmap_screen; + + fb_set_cmap(&info->cmap, info); - dev_set_drvdata(&op->dev, all); + cg3_init_fix(info, linebytes, dp); + + err = register_framebuffer(info); + if (err < 0) + goto out_dealloc_cmap; + + dev_set_drvdata(&op->dev, info); printk("%s: cg3 at %lx:%lx\n", - dp->full_name, all->par.which_io, all->par.physbase); + dp->full_name, par->which_io, par->physbase); return 0; -} -static int __devinit cg3_probe(struct of_device *dev, - const struct of_device_id *match) -{ - struct of_device *op = to_of_device(&dev->dev); +out_dealloc_cmap: + fb_dealloc_cmap(&info->cmap); + +out_unmap_screen: + of_iounmap(&op->resource[0], info->screen_base, par->fbsize); + +out_unmap_regs: + of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); + +out_release_fb: + framebuffer_release(info); - return cg3_init_one(op); +out_err: + return err; } static int __devexit cg3_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&op->dev); + struct fb_info *info = dev_get_drvdata(&op->dev); + struct cg3_par *par = info->par; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); - of_iounmap(&op->resource[0], all->par.regs, sizeof(struct cg3_regs)); - of_iounmap(&op->resource[0], all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); + of_iounmap(&op->resource[0], info->screen_base, par->fbsize); - kfree(all); + framebuffer_release(info); dev_set_drvdata(&op->dev, NULL); diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 4dad23a28f5..87c74712353 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c @@ -653,135 +653,120 @@ static void cg6_chip_init(struct fb_info *info) sbus_writel(info->var.yres - 1, &fbc->clipmaxy); } -struct all_info { - struct fb_info info; - struct cg6_par par; -}; - -static void cg6_unmap_regs(struct of_device *op, struct all_info *all) +static void cg6_unmap_regs(struct of_device *op, struct fb_info *info, + struct cg6_par *par) { - if (all->par.fbc) - of_iounmap(&op->resource[0], all->par.fbc, 4096); - if (all->par.tec) - of_iounmap(&op->resource[0], - all->par.tec, sizeof(struct cg6_tec)); - if (all->par.thc) - of_iounmap(&op->resource[0], - all->par.thc, sizeof(struct cg6_thc)); - if (all->par.bt) - of_iounmap(&op->resource[0], - all->par.bt, sizeof(struct bt_regs)); - if (all->par.fhc) - of_iounmap(&op->resource[0], - all->par.fhc, sizeof(u32)); - - if (all->info.screen_base) - of_iounmap(&op->resource[0], - all->info.screen_base, all->par.fbsize); + if (par->fbc) + of_iounmap(&op->resource[0], par->fbc, 4096); + if (par->tec) + of_iounmap(&op->resource[0], par->tec, sizeof(struct cg6_tec)); + if (par->thc) + of_iounmap(&op->resource[0], par->thc, sizeof(struct cg6_thc)); + if (par->bt) + of_iounmap(&op->resource[0], par->bt, sizeof(struct bt_regs)); + if (par->fhc) + of_iounmap(&op->resource[0], par->fhc, sizeof(u32)); + + if (info->screen_base) + of_iounmap(&op->resource[0], info->screen_base, par->fbsize); } -static int __devinit cg6_init_one(struct of_device *op) +static int __devinit cg6_probe(struct of_device *op, const struct of_device_id *match) { struct device_node *dp = op->node; - struct all_info *all; + struct fb_info *info; + struct cg6_par *par; int linebytes, err; - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + info = framebuffer_alloc(sizeof(struct cg6_par), &op->dev); + + err = -ENOMEM; + if (!info) + goto out_err; + par = info->par; - spin_lock_init(&all->par.lock); + spin_lock_init(&par->lock); - all->par.physbase = op->resource[0].start; - all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; + par->physbase = op->resource[0].start; + par->which_io = op->resource[0].flags & IORESOURCE_BITS; - sbusfb_fill_var(&all->info.var, dp->node, 8); - all->info.var.red.length = 8; - all->info.var.green.length = 8; - all->info.var.blue.length = 8; + sbusfb_fill_var(&info->var, dp->node, 8); + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); - all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + info->var.xres); + par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); if (of_find_property(dp, "dblbuf", NULL)) - all->par.fbsize *= 4; + par->fbsize *= 4; - all->par.fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET, + par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET, 4096, "cgsix fbc"); - all->par.tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET, + par->tec = of_ioremap(&op->resource[0], CG6_TEC_OFFSET, sizeof(struct cg6_tec), "cgsix tec"); - all->par.thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET, + par->thc = of_ioremap(&op->resource[0], CG6_THC_OFFSET, sizeof(struct cg6_thc), "cgsix thc"); - all->par.bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET, + par->bt = of_ioremap(&op->resource[0], CG6_BROOKTREE_OFFSET, sizeof(struct bt_regs), "cgsix dac"); - all->par.fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET, + par->fhc = of_ioremap(&op->resource[0], CG6_FHC_OFFSET, sizeof(u32), "cgsix fhc"); - all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT | + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; - all->info.fbops = &cg6_ops; - - all->info.screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, - all->par.fbsize, "cgsix ram"); - if (!all->par.fbc || !all->par.tec || !all->par.thc || - !all->par.bt || !all->par.fhc || !all->info.screen_base) { - cg6_unmap_regs(op, all); - kfree(all); - return -ENOMEM; - } + info->fbops = &cg6_ops; - all->info.par = &all->par; + info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, + par->fbsize, "cgsix ram"); + if (!par->fbc || !par->tec || !par->thc || + !par->bt || !par->fhc || !info->screen_base) + goto out_unmap_regs; - all->info.var.accel_flags = FB_ACCELF_TEXT; + info->var.accel_flags = FB_ACCELF_TEXT; - cg6_bt_init(&all->par); - cg6_chip_init(&all->info); - cg6_blank(0, &all->info); + cg6_bt_init(par); + cg6_chip_init(info); + cg6_blank(0, info); - if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - cg6_unmap_regs(op, all); - kfree(all); - return -ENOMEM; - } + if (fb_alloc_cmap(&info->cmap, 256, 0)) + goto out_unmap_regs; - fb_set_cmap(&all->info.cmap, &all->info); - cg6_init_fix(&all->info, linebytes); + fb_set_cmap(&info->cmap, info); + cg6_init_fix(info, linebytes); - err = register_framebuffer(&all->info); - if (err < 0) { - cg6_unmap_regs(op, all); - fb_dealloc_cmap(&all->info.cmap); - kfree(all); - return err; - } + err = register_framebuffer(info); + if (err < 0) + goto out_dealloc_cmap; - dev_set_drvdata(&op->dev, all); + dev_set_drvdata(&op->dev, info); printk("%s: CGsix [%s] at %lx:%lx\n", - dp->full_name, - all->info.fix.id, - all->par.which_io, all->par.physbase); + dp->full_name, info->fix.id, + par->which_io, par->physbase); return 0; -} -static int __devinit cg6_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct of_device *op = to_of_device(&dev->dev); +out_dealloc_cmap: + fb_dealloc_cmap(&info->cmap); + +out_unmap_regs: + cg6_unmap_regs(op, info, par); - return cg6_init_one(op); +out_err: + return err; } static int __devexit cg6_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&op->dev); + struct fb_info *info = dev_get_drvdata(&op->dev); + struct cg6_par *par = info->par; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); - cg6_unmap_regs(op, all); + cg6_unmap_regs(op, info, par); - kfree(all); + framebuffer_release(info); dev_set_drvdata(&op->dev, NULL); diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c index 3f6c98fad43..4b520b57391 100644 --- a/drivers/video/ffb.c +++ b/drivers/video/ffb.c @@ -371,6 +371,8 @@ struct ffb_par { unsigned long fbsize; int board_type; + + u32 pseudo_palette[16]; }; static void FFBFifo(struct ffb_par *par, int n) @@ -900,75 +902,67 @@ ffb_init_fix(struct fb_info *info) info->fix.accel = FB_ACCEL_SUN_CREATOR; } -struct all_info { - struct fb_info info; - struct ffb_par par; - u32 pseudo_palette[16]; -}; - -static int ffb_init_one(struct of_device *op) +static int __devinit ffb_probe(struct of_device *op, const struct of_device_id *match) { struct device_node *dp = op->node; struct ffb_fbc __iomem *fbc; struct ffb_dac __iomem *dac; - struct all_info *all; - int err; + struct fb_info *info; + struct ffb_par *par; u32 dac_pnum, dac_rev, dac_mrev; + int err; - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + info = framebuffer_alloc(sizeof(struct ffb_par), &op->dev); - spin_lock_init(&all->par.lock); - all->par.fbc = of_ioremap(&op->resource[2], 0, - sizeof(struct ffb_fbc), "ffb fbc"); - if (!all->par.fbc) { - kfree(all); - return -ENOMEM; - } + err = -ENOMEM; + if (!info) + goto out_err; - all->par.dac = of_ioremap(&op->resource[1], 0, - sizeof(struct ffb_dac), "ffb dac"); - if (!all->par.dac) { - of_iounmap(&op->resource[2], - all->par.fbc, sizeof(struct ffb_fbc)); - kfree(all); - return -ENOMEM; - } + par = info->par; + + spin_lock_init(&par->lock); + par->fbc = of_ioremap(&op->resource[2], 0, + sizeof(struct ffb_fbc), "ffb fbc"); + if (!par->fbc) + goto out_release_fb; + + par->dac = of_ioremap(&op->resource[1], 0, + sizeof(struct ffb_dac), "ffb dac"); + if (!par->dac) + goto out_unmap_fbc; - all->par.rop_cache = FFB_ROP_NEW; - all->par.physbase = op->resource[0].start; + par->rop_cache = FFB_ROP_NEW; + par->physbase = op->resource[0].start; /* Don't mention copyarea, so SCROLL_REDRAW is always * used. It is the fastest on this chip. */ - all->info.flags = (FBINFO_DEFAULT | - /* FBINFO_HWACCEL_COPYAREA | */ - FBINFO_HWACCEL_FILLRECT | - FBINFO_HWACCEL_IMAGEBLIT); - all->info.fbops = &ffb_ops; - all->info.screen_base = (char *) all->par.physbase + FFB_DFB24_POFF; - all->info.par = &all->par; - all->info.pseudo_palette = all->pseudo_palette; - - sbusfb_fill_var(&all->info.var, dp->node, 32); - all->par.fbsize = PAGE_ALIGN(all->info.var.xres * - all->info.var.yres * - 4); - ffb_fixup_var_rgb(&all->info.var); - - all->info.var.accel_flags = FB_ACCELF_TEXT; + info->flags = (FBINFO_DEFAULT | + /* FBINFO_HWACCEL_COPYAREA | */ + FBINFO_HWACCEL_FILLRECT | + FBINFO_HWACCEL_IMAGEBLIT); + + info->fbops = &ffb_ops; + + info->screen_base = (char *) par->physbase + FFB_DFB24_POFF; + info->pseudo_palette = par->pseudo_palette; + + sbusfb_fill_var(&info->var, dp->node, 32); + par->fbsize = PAGE_ALIGN(info->var.xres * info->var.yres * 4); + ffb_fixup_var_rgb(&info->var); + + info->var.accel_flags = FB_ACCELF_TEXT; if (!strcmp(dp->name, "SUNW,afb")) - all->par.flags |= FFB_FLAG_AFB; + par->flags |= FFB_FLAG_AFB; - all->par.board_type = of_getintprop_default(dp, "board_type", 0); + par->board_type = of_getintprop_default(dp, "board_type", 0); - fbc = all->par.fbc; + fbc = par->fbc; if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr); - dac = all->par.dac; + dac = par->dac; upa_writel(FFB_DAC_DID, &dac->type); dac_pnum = upa_readl(&dac->value); dac_rev = (dac_pnum & FFB_DAC_DID_REV) >> FFB_DAC_DID_REV_SHIFT; @@ -985,76 +979,70 @@ static int ffb_init_one(struct of_device *op) * cursor logic. We identify Pacifica 1 as not Pacifica 2, the * latter having a part number value of 0x236e. */ - if ((all->par.flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) { - all->par.flags &= ~FFB_FLAG_INVCURSOR; + if ((par->flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) { + par->flags &= ~FFB_FLAG_INVCURSOR; } else { if (dac_mrev < 3) - all->par.flags |= FFB_FLAG_INVCURSOR; + par->flags |= FFB_FLAG_INVCURSOR; } - ffb_switch_from_graph(&all->par); + ffb_switch_from_graph(par); /* Unblank it just to be sure. When there are multiple * FFB/AFB cards in the system, or it is not the OBP * chosen console, it will have video outputs off in * the DAC. */ - ffb_blank(0, &all->info); - - if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - printk(KERN_ERR "ffb: Could not allocate color map.\n"); - of_iounmap(&op->resource[2], - all->par.fbc, sizeof(struct ffb_fbc)); - of_iounmap(&op->resource[1], - all->par.dac, sizeof(struct ffb_dac)); - kfree(all); - return -ENOMEM; - } + ffb_blank(0, info); - ffb_init_fix(&all->info); - - err = register_framebuffer(&all->info); - if (err < 0) { - printk(KERN_ERR "ffb: Could not register framebuffer.\n"); - fb_dealloc_cmap(&all->info.cmap); - of_iounmap(&op->resource[2], - all->par.fbc, sizeof(struct ffb_fbc)); - of_iounmap(&op->resource[1], - all->par.dac, sizeof(struct ffb_dac)); - kfree(all); - return err; - } + if (fb_alloc_cmap(&info->cmap, 256, 0)) + goto out_unmap_dac; + + ffb_init_fix(info); - dev_set_drvdata(&op->dev, all); + err = register_framebuffer(info); + if (err < 0) + goto out_dealloc_cmap; + + dev_set_drvdata(&op->dev, info); printk("%s: %s at %016lx, type %d, " "DAC pnum[%x] rev[%d] manuf_rev[%d]\n", dp->full_name, - ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), - all->par.physbase, all->par.board_type, + ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), + par->physbase, par->board_type, dac_pnum, dac_rev, dac_mrev); return 0; -} -static int __devinit ffb_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct of_device *op = to_of_device(&dev->dev); +out_dealloc_cmap: + fb_dealloc_cmap(&info->cmap); + +out_unmap_dac: + of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc)); + +out_unmap_fbc: + of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc)); + +out_release_fb: + framebuffer_release(info); - return ffb_init_one(op); +out_err: + return err; } static int __devexit ffb_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&op->dev); + struct fb_info *info = dev_get_drvdata(&op->dev); + struct ffb_par *par = info->par; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); - of_iounmap(&op->resource[2], all->par.fbc, sizeof(struct ffb_fbc)); - of_iounmap(&op->resource[1], all->par.dac, sizeof(struct ffb_dac)); + of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc)); + of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac)); - kfree(all); + framebuffer_release(info); dev_set_drvdata(&op->dev, NULL); diff --git a/drivers/video/leo.c b/drivers/video/leo.c index a038aa5a9e1..45b9a5d55de 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c @@ -525,130 +525,123 @@ static void leo_fixup_var_rgb(struct fb_var_screeninfo *var) var->transp.length = 0; } -struct all_info { - struct fb_info info; - struct leo_par par; -}; - -static void leo_unmap_regs(struct of_device *op, struct all_info *all) +static void leo_unmap_regs(struct of_device *op, struct fb_info *info, + struct leo_par *par) { - if (all->par.lc_ss0_usr) - of_iounmap(&op->resource[0], all->par.lc_ss0_usr, 0x1000); - if (all->par.ld_ss0) - of_iounmap(&op->resource[0], all->par.ld_ss0, 0x1000); - if (all->par.ld_ss1) - of_iounmap(&op->resource[0], all->par.ld_ss1, 0x1000); - if (all->par.lx_krn) - of_iounmap(&op->resource[0], all->par.lx_krn, 0x1000); - if (all->par.cursor) + if (par->lc_ss0_usr) + of_iounmap(&op->resource[0], par->lc_ss0_usr, 0x1000); + if (par->ld_ss0) + of_iounmap(&op->resource[0], par->ld_ss0, 0x1000); + if (par->ld_ss1) + of_iounmap(&op->resource[0], par->ld_ss1, 0x1000); + if (par->lx_krn) + of_iounmap(&op->resource[0], par->lx_krn, 0x1000); + if (par->cursor) of_iounmap(&op->resource[0], - all->par.cursor, sizeof(struct leo_cursor)); - if (all->info.screen_base) - of_iounmap(&op->resource[0], all->info.screen_base, 0x800000); + par->cursor, sizeof(struct leo_cursor)); + if (info->screen_base) + of_iounmap(&op->resource[0], info->screen_base, 0x800000); } -static int __devinit leo_init_one(struct of_device *op) +static int __devinit leo_probe(struct of_device *op, const struct of_device_id *match) { struct device_node *dp = op->node; - struct all_info *all; + struct fb_info *info; + struct leo_par *par; int linebytes, err; - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + info = framebuffer_alloc(sizeof(struct leo_par), &op->dev); + + err = -ENOMEM; + if (!info) + goto out_err; + par = info->par; - spin_lock_init(&all->par.lock); + spin_lock_init(&par->lock); - all->par.physbase = op->resource[0].start; - all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; + par->physbase = op->resource[0].start; + par->which_io = op->resource[0].flags & IORESOURCE_BITS; - sbusfb_fill_var(&all->info.var, dp->node, 32); - leo_fixup_var_rgb(&all->info.var); + sbusfb_fill_var(&info->var, dp->node, 32); + leo_fixup_var_rgb(&info->var); linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); - all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + info->var.xres); + par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); - all->par.lc_ss0_usr = + par->lc_ss0_usr = of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, 0x1000, "leolc ss0usr"); - all->par.ld_ss0 = + par->ld_ss0 = of_ioremap(&op->resource[0], LEO_OFF_LD_SS0, 0x1000, "leold ss0"); - all->par.ld_ss1 = + par->ld_ss1 = of_ioremap(&op->resource[0], LEO_OFF_LD_SS1, 0x1000, "leold ss1"); - all->par.lx_krn = + par->lx_krn = of_ioremap(&op->resource[0], LEO_OFF_LX_KRN, 0x1000, "leolx krn"); - all->par.cursor = + par->cursor = of_ioremap(&op->resource[0], LEO_OFF_LX_CURSOR, sizeof(struct leo_cursor), "leolx cursor"); - all->info.screen_base = + info->screen_base = of_ioremap(&op->resource[0], LEO_OFF_SS0, 0x800000, "leo ram"); - if (!all->par.lc_ss0_usr || - !all->par.ld_ss0 || - !all->par.ld_ss1 || - !all->par.lx_krn || - !all->par.cursor || - !all->info.screen_base) { - leo_unmap_regs(op, all); - kfree(all); - return -ENOMEM; - } + if (!par->lc_ss0_usr || + !par->ld_ss0 || + !par->ld_ss1 || + !par->lx_krn || + !par->cursor || + !info->screen_base) + goto out_unmap_regs; - all->info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; - all->info.fbops = &leo_ops; - all->info.par = &all->par; + info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN; + info->fbops = &leo_ops; - leo_init_wids(&all->info); - leo_init_hw(&all->info); + leo_init_wids(info); + leo_init_hw(info); - leo_blank(0, &all->info); + leo_blank(0, info); - if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - leo_unmap_regs(op, all); - kfree(all); - return -ENOMEM;; - } + if (fb_alloc_cmap(&info->cmap, 256, 0)) + goto out_unmap_regs; - leo_init_fix(&all->info, dp); + leo_init_fix(info, dp); - err = register_framebuffer(&all->info); - if (err < 0) { - fb_dealloc_cmap(&all->info.cmap); - leo_unmap_regs(op, all); - kfree(all); - return err; - } + err = register_framebuffer(info); + if (err < 0) + goto out_dealloc_cmap; - dev_set_drvdata(&op->dev, all); + dev_set_drvdata(&op->dev, info); printk("%s: leo at %lx:%lx\n", dp->full_name, - all->par.which_io, all->par.physbase); + par->which_io, par->physbase); return 0; -} -static int __devinit leo_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct of_device *op = to_of_device(&dev->dev); +out_dealloc_cmap: + fb_dealloc_cmap(&info->cmap); + +out_unmap_regs: + leo_unmap_regs(op, info, par); + framebuffer_release(info); - return leo_init_one(op); +out_err: + return err; } static int __devexit leo_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&op->dev); + struct fb_info *info = dev_get_drvdata(&op->dev); + struct leo_par *par = info->par; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); - leo_unmap_regs(op, all); + leo_unmap_regs(op, info, par); - kfree(all); + framebuffer_release(info); dev_set_drvdata(&op->dev, NULL); diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 637b78bb4bf..58496061142 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c @@ -255,107 +255,95 @@ static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_no info->fix.accel = FB_ACCEL_SUN_CGTHREE; } -struct all_info { - struct fb_info info; - struct p9100_par par; -}; - -static int __devinit p9100_init_one(struct of_device *op) +static int __devinit p9100_probe(struct of_device *op, const struct of_device_id *match) { struct device_node *dp = op->node; - struct all_info *all; + struct fb_info *info; + struct p9100_par *par; int linebytes, err; - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + info = framebuffer_alloc(sizeof(struct p9100_par), &op->dev); + + err = -ENOMEM; + if (!info) + goto out_err; + par = info->par; - spin_lock_init(&all->par.lock); + spin_lock_init(&par->lock); /* This is the framebuffer and the only resource apps can mmap. */ - all->par.physbase = op->resource[2].start; - all->par.which_io = op->resource[2].flags & IORESOURCE_BITS; - - sbusfb_fill_var(&all->info.var, dp->node, 8); - all->info.var.red.length = 8; - all->info.var.green.length = 8; - all->info.var.blue.length = 8; - - linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); - all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); - - all->par.regs = of_ioremap(&op->resource[0], 0, - sizeof(struct p9100_regs), "p9100 regs"); - if (!all->par.regs) { - kfree(all); - return -ENOMEM; - } + par->physbase = op->resource[2].start; + par->which_io = op->resource[2].flags & IORESOURCE_BITS; - all->info.flags = FBINFO_DEFAULT; - all->info.fbops = &p9100_ops; - all->info.screen_base = of_ioremap(&op->resource[2], 0, - all->par.fbsize, "p9100 ram"); - if (!all->info.screen_base) { - of_iounmap(&op->resource[0], - all->par.regs, sizeof(struct p9100_regs)); - kfree(all); - return -ENOMEM; - } - all->info.par = &all->par; + sbusfb_fill_var(&info->var, dp->node, 8); + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; - p9100_blank(0, &all->info); + linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); + par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); - if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - of_iounmap(&op->resource[0], - all->par.regs, sizeof(struct p9100_regs)); - of_iounmap(&op->resource[2], - all->info.screen_base, all->par.fbsize); - kfree(all); - return -ENOMEM; - } + par->regs = of_ioremap(&op->resource[0], 0, + sizeof(struct p9100_regs), "p9100 regs"); + if (!par->regs) + goto out_release_fb; - p9100_init_fix(&all->info, linebytes, dp); - - err = register_framebuffer(&all->info); - if (err < 0) { - fb_dealloc_cmap(&all->info.cmap); - of_iounmap(&op->resource[0], - all->par.regs, sizeof(struct p9100_regs)); - of_iounmap(&op->resource[2], - all->info.screen_base, all->par.fbsize); - kfree(all); - return err; - } - fb_set_cmap(&all->info.cmap, &all->info); + info->flags = FBINFO_DEFAULT; + info->fbops = &p9100_ops; + info->screen_base = of_ioremap(&op->resource[2], 0, + par->fbsize, "p9100 ram"); + if (!info->screen_base) + goto out_unmap_regs; + + p9100_blank(0, info); + + if (fb_alloc_cmap(&info->cmap, 256, 0)) + goto out_unmap_screen; - dev_set_drvdata(&op->dev, all); + p9100_init_fix(info, linebytes, dp); + + err = register_framebuffer(info); + if (err < 0) + goto out_dealloc_cmap; + + fb_set_cmap(&info->cmap, info); + + dev_set_drvdata(&op->dev, info); printk("%s: p9100 at %lx:%lx\n", dp->full_name, - all->par.which_io, all->par.physbase); + par->which_io, par->physbase); return 0; -} -static int __devinit p9100_probe(struct of_device *dev, const struct of_device_id *match) -{ - struct of_device *op = to_of_device(&dev->dev); +out_dealloc_cmap: + fb_dealloc_cmap(&info->cmap); + +out_unmap_screen: + of_iounmap(&op->resource[2], info->screen_base, par->fbsize); + +out_unmap_regs: + of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); + +out_release_fb: + framebuffer_release(info); - return p9100_init_one(op); +out_err: + return err; } static int __devexit p9100_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&op->dev); + struct fb_info *info = dev_get_drvdata(&op->dev); + struct p9100_par *par = info->par; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); - of_iounmap(&op->resource[0], all->par.regs, sizeof(struct p9100_regs)); - of_iounmap(&op->resource[2], all->info.screen_base, all->par.fbsize); + of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); + of_iounmap(&op->resource[2], info->screen_base, par->fbsize); - kfree(all); + framebuffer_release(info); dev_set_drvdata(&op->dev, NULL); diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c index 5a99669232c..e5a9ddb3c8b 100644 --- a/drivers/video/tcx.c +++ b/drivers/video/tcx.c @@ -345,88 +345,82 @@ tcx_init_fix(struct fb_info *info, int linebytes) info->fix.accel = FB_ACCEL_SUN_TCX; } -struct all_info { - struct fb_info info; - struct tcx_par par; -}; - -static void tcx_unmap_regs(struct of_device *op, struct all_info *all) +static void tcx_unmap_regs(struct of_device *op, struct fb_info *info, + struct tcx_par *par) { - if (all->par.tec) + if (par->tec) of_iounmap(&op->resource[7], - all->par.tec, sizeof(struct tcx_tec)); - if (all->par.thc) + par->tec, sizeof(struct tcx_tec)); + if (par->thc) of_iounmap(&op->resource[9], - all->par.thc, sizeof(struct tcx_thc)); - if (all->par.bt) + par->thc, sizeof(struct tcx_thc)); + if (par->bt) of_iounmap(&op->resource[8], - all->par.bt, sizeof(struct bt_regs)); - if (all->par.cplane) + par->bt, sizeof(struct bt_regs)); + if (par->cplane) of_iounmap(&op->resource[4], - all->par.cplane, all->par.fbsize * sizeof(u32)); - if (all->info.screen_base) + par->cplane, par->fbsize * sizeof(u32)); + if (info->screen_base) of_iounmap(&op->resource[0], - all->info.screen_base, all->par.fbsize); + info->screen_base, par->fbsize); } static int __devinit tcx_init_one(struct of_device *op) { struct device_node *dp = op->node; - struct all_info *all; + struct fb_info *info; + struct tcx_par *par; int linebytes, i, err; - all = kzalloc(sizeof(*all), GFP_KERNEL); - if (!all) - return -ENOMEM; + info = framebuffer_alloc(sizeof(struct tcx_par), &op->dev); - spin_lock_init(&all->par.lock); + err = -ENOMEM; + if (!info) + goto out_err; + par = info->par; - all->par.lowdepth = + spin_lock_init(&par->lock); + + par->lowdepth = (of_find_property(dp, "tcx-8-bit", NULL) != NULL); - sbusfb_fill_var(&all->info.var, dp->node, 8); - all->info.var.red.length = 8; - all->info.var.green.length = 8; - all->info.var.blue.length = 8; + sbusfb_fill_var(&info->var, dp->node, 8); + info->var.red.length = 8; + info->var.green.length = 8; + info->var.blue.length = 8; linebytes = of_getintprop_default(dp, "linebytes", - all->info.var.xres); - all->par.fbsize = PAGE_ALIGN(linebytes * all->info.var.yres); + info->var.xres); + par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); - all->par.tec = of_ioremap(&op->resource[7], 0, + par->tec = of_ioremap(&op->resource[7], 0, sizeof(struct tcx_tec), "tcx tec"); - all->par.thc = of_ioremap(&op->resource[9], 0, + par->thc = of_ioremap(&op->resource[9], 0, sizeof(struct tcx_thc), "tcx thc"); - all->par.bt = of_ioremap(&op->resource[8], 0, + par->bt = of_ioremap(&op->resource[8], 0, sizeof(struct bt_regs), "tcx dac"); - all->info.screen_base = of_ioremap(&op->resource[0], 0, - all->par.fbsize, "tcx ram"); - if (!all->par.tec || !all->par.thc || - !all->par.bt || !all->info.screen_base) { - tcx_unmap_regs(op, all); - kfree(all); - return -ENOMEM; - } - - memcpy(&all->par.mmap_map, &__tcx_mmap_map, sizeof(all->par.mmap_map)); - if (!all->par.lowdepth) { - all->par.cplane = of_ioremap(&op->resource[4], 0, - all->par.fbsize * sizeof(u32), + info->screen_base = of_ioremap(&op->resource[0], 0, + par->fbsize, "tcx ram"); + if (!par->tec || !par->thc || + !par->bt || !info->screen_base) + goto out_unmap_regs; + + memcpy(&par->mmap_map, &__tcx_mmap_map, sizeof(par->mmap_map)); + if (!par->lowdepth) { + par->cplane = of_ioremap(&op->resource[4], 0, + par->fbsize * sizeof(u32), "tcx cplane"); - if (!all->par.cplane) { - tcx_unmap_regs(op, all); - kfree(all); - return -ENOMEM; - } + if (!par->cplane) + goto out_unmap_regs; } else { - all->par.mmap_map[1].size = SBUS_MMAP_EMPTY; - all->par.mmap_map[4].size = SBUS_MMAP_EMPTY; - all->par.mmap_map[5].size = SBUS_MMAP_EMPTY; - all->par.mmap_map[6].size = SBUS_MMAP_EMPTY; + par->mmap_map[1].size = SBUS_MMAP_EMPTY; + par->mmap_map[4].size = SBUS_MMAP_EMPTY; + par->mmap_map[5].size = SBUS_MMAP_EMPTY; + par->mmap_map[6].size = SBUS_MMAP_EMPTY; } - all->par.physbase = 0; - all->par.which_io = op->resource[0].flags & IORESOURCE_BITS; + par->physbase = 0; + par->which_io = op->resource[0].flags & IORESOURCE_BITS; for (i = 0; i < TCX_MMAP_ENTRIES; i++) { int j; @@ -444,53 +438,54 @@ static int __devinit tcx_init_one(struct of_device *op) j = i; break; }; - all->par.mmap_map[i].poff = op->resource[j].start; + par->mmap_map[i].poff = op->resource[j].start; } - all->info.flags = FBINFO_DEFAULT; - all->info.fbops = &tcx_ops; - all->info.par = &all->par; + info->flags = FBINFO_DEFAULT; + info->fbops = &tcx_ops; /* Initialize brooktree DAC. */ - sbus_writel(0x04 << 24, &all->par.bt->addr); /* color planes */ - sbus_writel(0xff << 24, &all->par.bt->control); - sbus_writel(0x05 << 24, &all->par.bt->addr); - sbus_writel(0x00 << 24, &all->par.bt->control); - sbus_writel(0x06 << 24, &all->par.bt->addr); /* overlay plane */ - sbus_writel(0x73 << 24, &all->par.bt->control); - sbus_writel(0x07 << 24, &all->par.bt->addr); - sbus_writel(0x00 << 24, &all->par.bt->control); - - tcx_reset(&all->info); - - tcx_blank(FB_BLANK_UNBLANK, &all->info); - - if (fb_alloc_cmap(&all->info.cmap, 256, 0)) { - tcx_unmap_regs(op, all); - kfree(all); - return -ENOMEM; - } + sbus_writel(0x04 << 24, &par->bt->addr); /* color planes */ + sbus_writel(0xff << 24, &par->bt->control); + sbus_writel(0x05 << 24, &par->bt->addr); + sbus_writel(0x00 << 24, &par->bt->control); + sbus_writel(0x06 << 24, &par->bt->addr); /* overlay plane */ + sbus_writel(0x73 << 24, &par->bt->control); + sbus_writel(0x07 << 24, &par->bt->addr); + sbus_writel(0x00 << 24, &par->bt->control); + + tcx_reset(info); - fb_set_cmap(&all->info.cmap, &all->info); - tcx_init_fix(&all->info, linebytes); + tcx_blank(FB_BLANK_UNBLANK, info); - err = register_framebuffer(&all->info); - if (err < 0) { - fb_dealloc_cmap(&all->info.cmap); - tcx_unmap_regs(op, all); - kfree(all); - return err; - } + if (fb_alloc_cmap(&info->cmap, 256, 0)) + goto out_unmap_regs; + + fb_set_cmap(&info->cmap, info); + tcx_init_fix(info, linebytes); + + err = register_framebuffer(info); + if (err < 0) + goto out_dealloc_cmap; - dev_set_drvdata(&op->dev, all); + dev_set_drvdata(&op->dev, info); printk("%s: TCX at %lx:%lx, %s\n", dp->full_name, - all->par.which_io, + par->which_io, op->resource[0].start, - all->par.lowdepth ? "8-bit only" : "24-bit depth"); + par->lowdepth ? "8-bit only" : "24-bit depth"); return 0; + +out_dealloc_cmap: + fb_dealloc_cmap(&info->cmap); + +out_unmap_regs: + tcx_unmap_regs(op, info, par); + +out_err: + return err; } static int __devinit tcx_probe(struct of_device *dev, const struct of_device_id *match) @@ -502,14 +497,15 @@ static int __devinit tcx_probe(struct of_device *dev, const struct of_device_id static int __devexit tcx_remove(struct of_device *op) { - struct all_info *all = dev_get_drvdata(&op->dev); + struct fb_info *info = dev_get_drvdata(&op->dev); + struct tcx_par *par = info->par; - unregister_framebuffer(&all->info); - fb_dealloc_cmap(&all->info.cmap); + unregister_framebuffer(info); + fb_dealloc_cmap(&info->cmap); - tcx_unmap_regs(op, all); + tcx_unmap_regs(op, info, par); - kfree(all); + framebuffer_release(info); dev_set_drvdata(&op->dev, NULL); -- cgit v1.2.3 From ad7ad57c6127042c411353dddb723765964815db Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 27 Jul 2007 22:39:14 -0700 Subject: [SPARC64]: Fix conflicts in SBUS/PCI/EBUS/ISA DMA handling. Fully unify all of the DMA ops so that subordinate bus types to the DMA operation providers (such as ebus, isa, of_device) can work transparently. Basically, we just make sure that for every system device we create, the dev->archdata 'iommu' and 'stc' fields are filled in. Then we have two platform variants of the DMA ops, one for SUN4U which actually programs the real hardware, and one for SUN4V which makes hypervisor calls. This also fixes the crashes in parport_pc on sparc64, reported by Meelis Roos. Signed-off-by: David S. Miller --- arch/sparc64/kernel/Makefile | 4 +- arch/sparc64/kernel/ebus.c | 2 + arch/sparc64/kernel/iommu.c | 809 +++++++++++++++++++++++++++++++++++++ arch/sparc64/kernel/isa.c | 2 + arch/sparc64/kernel/pci.c | 62 ++- arch/sparc64/kernel/pci_fire.c | 24 +- arch/sparc64/kernel/pci_iommu.c | 823 -------------------------------------- arch/sparc64/kernel/pci_psycho.c | 32 +- arch/sparc64/kernel/pci_sabre.c | 35 +- arch/sparc64/kernel/pci_schizo.c | 42 +- arch/sparc64/kernel/pci_sun4v.c | 168 ++++---- arch/sparc64/kernel/sbus.c | 568 ++------------------------ drivers/sbus/sbus.c | 9 + include/asm-sparc/device.h | 4 + include/asm-sparc64/dma-mapping.h | 337 ++++------------ include/asm-sparc64/iommu.h | 11 +- include/asm-sparc64/parport.h | 2 +- include/asm-sparc64/pci.h | 152 ++----- include/asm-sparc64/sbus.h | 86 +++- 19 files changed, 1284 insertions(+), 1888 deletions(-) create mode 100644 arch/sparc64/kernel/iommu.c delete mode 100644 arch/sparc64/kernel/pci_iommu.c diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index b66876bf410..40d2f3aae91 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -8,14 +8,14 @@ EXTRA_CFLAGS := -Werror extra-y := head.o init_task.o vmlinux.lds obj-y := process.o setup.o cpu.o idprom.o \ - traps.o auxio.o una_asm.o sysfs.o \ + traps.o auxio.o una_asm.o sysfs.o iommu.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o central.o pci.o starfire.o semaphore.o \ power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \ visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o -obj-$(CONFIG_PCI) += ebus.o isa.o pci_common.o pci_iommu.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_SMP) += smp.o trampoline.o hvtramp.o diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 6d2956179cd..bc9ae36f7a4 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -391,6 +391,8 @@ static void __init fill_ebus_device(struct device_node *dp, struct linux_ebus_de sd = &dev->ofdev.dev.archdata; sd->prom_node = dp; sd->op = &dev->ofdev; + sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu; + sd->stc = dev->bus->ofdev.dev.parent->archdata.stc; dev->ofdev.node = dp; dev->ofdev.dev.parent = &dev->bus->ofdev.dev; diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c new file mode 100644 index 00000000000..b35a62167e9 --- /dev/null +++ b/arch/sparc64/kernel/iommu.c @@ -0,0 +1,809 @@ +/* iommu.c: Generic sparc64 IOMMU support. + * + * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) + * Copyright (C) 1999, 2000 Jakub Jelinek (jakub@redhat.com) + */ + +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PCI +#include +#endif + +#include + +#include "iommu_common.h" + +#define STC_CTXMATCH_ADDR(STC, CTX) \ + ((STC)->strbuf_ctxmatch_base + ((CTX) << 3)) +#define STC_FLUSHFLAG_INIT(STC) \ + (*((STC)->strbuf_flushflag) = 0UL) +#define STC_FLUSHFLAG_SET(STC) \ + (*((STC)->strbuf_flushflag) != 0UL) + +#define iommu_read(__reg) \ +({ u64 __ret; \ + __asm__ __volatile__("ldxa [%1] %2, %0" \ + : "=r" (__ret) \ + : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ + : "memory"); \ + __ret; \ +}) +#define iommu_write(__reg, __val) \ + __asm__ __volatile__("stxa %0, [%1] %2" \ + : /* no outputs */ \ + : "r" (__val), "r" (__reg), \ + "i" (ASI_PHYS_BYPASS_EC_E)) + +/* Must be invoked under the IOMMU lock. */ +static void __iommu_flushall(struct iommu *iommu) +{ + if (iommu->iommu_flushinv) { + iommu_write(iommu->iommu_flushinv, ~(u64)0); + } else { + unsigned long tag; + int entry; + + tag = iommu->iommu_tags; + for (entry = 0; entry < 16; entry++) { + iommu_write(tag, 0); + tag += 8; + } + + /* Ensure completion of previous PIO writes. */ + (void) iommu_read(iommu->write_complete_reg); + } +} + +#define IOPTE_CONSISTENT(CTX) \ + (IOPTE_VALID | IOPTE_CACHE | \ + (((CTX) << 47) & IOPTE_CONTEXT)) + +#define IOPTE_STREAMING(CTX) \ + (IOPTE_CONSISTENT(CTX) | IOPTE_STBUF) + +/* Existing mappings are never marked invalid, instead they + * are pointed to a dummy page. + */ +#define IOPTE_IS_DUMMY(iommu, iopte) \ + ((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa) + +static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte) +{ + unsigned long val = iopte_val(*iopte); + + val &= ~IOPTE_PAGE; + val |= iommu->dummy_page_pa; + + iopte_val(*iopte) = val; +} + +/* Based largely upon the ppc64 iommu allocator. */ +static long arena_alloc(struct iommu *iommu, unsigned long npages) +{ + struct iommu_arena *arena = &iommu->arena; + unsigned long n, i, start, end, limit; + int pass; + + limit = arena->limit; + start = arena->hint; + pass = 0; + +again: + n = find_next_zero_bit(arena->map, limit, start); + end = n + npages; + if (unlikely(end >= limit)) { + if (likely(pass < 1)) { + limit = start; + start = 0; + __iommu_flushall(iommu); + pass++; + goto again; + } else { + /* Scanned the whole thing, give up. */ + return -1; + } + } + + for (i = n; i < end; i++) { + if (test_bit(i, arena->map)) { + start = i + 1; + goto again; + } + } + + for (i = n; i < end; i++) + __set_bit(i, arena->map); + + arena->hint = end; + + return n; +} + +static void arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages) +{ + unsigned long i; + + for (i = base; i < (base + npages); i++) + __clear_bit(i, arena->map); +} + +int iommu_table_init(struct iommu *iommu, int tsbsize, + u32 dma_offset, u32 dma_addr_mask) +{ + unsigned long i, tsbbase, order, sz, num_tsb_entries; + + num_tsb_entries = tsbsize / sizeof(iopte_t); + + /* Setup initial software IOMMU state. */ + spin_lock_init(&iommu->lock); + iommu->ctx_lowest_free = 1; + iommu->page_table_map_base = dma_offset; + iommu->dma_addr_mask = dma_addr_mask; + + /* Allocate and initialize the free area map. */ + sz = num_tsb_entries / 8; + sz = (sz + 7UL) & ~7UL; + iommu->arena.map = kzalloc(sz, GFP_KERNEL); + if (!iommu->arena.map) { + printk(KERN_ERR "IOMMU: Error, kmalloc(arena.map) failed.\n"); + return -ENOMEM; + } + iommu->arena.limit = num_tsb_entries; + + /* Allocate and initialize the dummy page which we + * set inactive IO PTEs to point to. + */ + iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); + if (!iommu->dummy_page) { + printk(KERN_ERR "IOMMU: Error, gfp(dummy_page) failed.\n"); + goto out_free_map; + } + memset((void *)iommu->dummy_page, 0, PAGE_SIZE); + iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); + + /* Now allocate and setup the IOMMU page table itself. */ + order = get_order(tsbsize); + tsbbase = __get_free_pages(GFP_KERNEL, order); + if (!tsbbase) { + printk(KERN_ERR "IOMMU: Error, gfp(tsb) failed.\n"); + goto out_free_dummy_page; + } + iommu->page_table = (iopte_t *)tsbbase; + + for (i = 0; i < num_tsb_entries; i++) + iopte_make_dummy(iommu, &iommu->page_table[i]); + + return 0; + +out_free_dummy_page: + free_page(iommu->dummy_page); + iommu->dummy_page = 0UL; + +out_free_map: + kfree(iommu->arena.map); + iommu->arena.map = NULL; + + return -ENOMEM; +} + +static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages) +{ + long entry; + + entry = arena_alloc(iommu, npages); + if (unlikely(entry < 0)) + return NULL; + + return iommu->page_table + entry; +} + +static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages) +{ + arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages); +} + +static int iommu_alloc_ctx(struct iommu *iommu) +{ + int lowest = iommu->ctx_lowest_free; + int sz = IOMMU_NUM_CTXS - lowest; + int n = find_next_zero_bit(iommu->ctx_bitmap, sz, lowest); + + if (unlikely(n == sz)) { + n = find_next_zero_bit(iommu->ctx_bitmap, lowest, 1); + if (unlikely(n == lowest)) { + printk(KERN_WARNING "IOMMU: Ran out of contexts.\n"); + n = 0; + } + } + if (n) + __set_bit(n, iommu->ctx_bitmap); + + return n; +} + +static inline void iommu_free_ctx(struct iommu *iommu, int ctx) +{ + if (likely(ctx)) { + __clear_bit(ctx, iommu->ctx_bitmap); + if (ctx < iommu->ctx_lowest_free) + iommu->ctx_lowest_free = ctx; + } +} + +static void *dma_4u_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_addrp, gfp_t gfp) +{ + struct iommu *iommu; + iopte_t *iopte; + unsigned long flags, order, first_page; + void *ret; + int npages; + + size = IO_PAGE_ALIGN(size); + order = get_order(size); + if (order >= 10) + return NULL; + + first_page = __get_free_pages(gfp, order); + if (first_page == 0UL) + return NULL; + memset((char *)first_page, 0, PAGE_SIZE << order); + + iommu = dev->archdata.iommu; + + spin_lock_irqsave(&iommu->lock, flags); + iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT); + spin_unlock_irqrestore(&iommu->lock, flags); + + if (unlikely(iopte == NULL)) { + free_pages(first_page, order); + return NULL; + } + + *dma_addrp = (iommu->page_table_map_base + + ((iopte - iommu->page_table) << IO_PAGE_SHIFT)); + ret = (void *) first_page; + npages = size >> IO_PAGE_SHIFT; + first_page = __pa(first_page); + while (npages--) { + iopte_val(*iopte) = (IOPTE_CONSISTENT(0UL) | + IOPTE_WRITE | + (first_page & IOPTE_PAGE)); + iopte++; + first_page += IO_PAGE_SIZE; + } + + return ret; +} + +static void dma_4u_free_coherent(struct device *dev, size_t size, + void *cpu, dma_addr_t dvma) +{ + struct iommu *iommu; + iopte_t *iopte; + unsigned long flags, order, npages; + + npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; + iommu = dev->archdata.iommu; + iopte = iommu->page_table + + ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + + spin_lock_irqsave(&iommu->lock, flags); + + free_npages(iommu, dvma - iommu->page_table_map_base, npages); + + spin_unlock_irqrestore(&iommu->lock, flags); + + order = get_order(size); + if (order < 10) + free_pages((unsigned long)cpu, order); +} + +static dma_addr_t dma_4u_map_single(struct device *dev, void *ptr, size_t sz, + enum dma_data_direction direction) +{ + struct iommu *iommu; + struct strbuf *strbuf; + iopte_t *base; + unsigned long flags, npages, oaddr; + unsigned long i, base_paddr, ctx; + u32 bus_addr, ret; + unsigned long iopte_protection; + + iommu = dev->archdata.iommu; + strbuf = dev->archdata.stc; + + if (unlikely(direction == DMA_NONE)) + goto bad_no_ctx; + + oaddr = (unsigned long)ptr; + npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); + npages >>= IO_PAGE_SHIFT; + + spin_lock_irqsave(&iommu->lock, flags); + base = alloc_npages(iommu, npages); + ctx = 0; + if (iommu->iommu_ctxflush) + ctx = iommu_alloc_ctx(iommu); + spin_unlock_irqrestore(&iommu->lock, flags); + + if (unlikely(!base)) + goto bad; + + bus_addr = (iommu->page_table_map_base + + ((base - iommu->page_table) << IO_PAGE_SHIFT)); + ret = bus_addr | (oaddr & ~IO_PAGE_MASK); + base_paddr = __pa(oaddr & IO_PAGE_MASK); + if (strbuf->strbuf_enabled) + iopte_protection = IOPTE_STREAMING(ctx); + else + iopte_protection = IOPTE_CONSISTENT(ctx); + if (direction != DMA_TO_DEVICE) + iopte_protection |= IOPTE_WRITE; + + for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE) + iopte_val(*base) = iopte_protection | base_paddr; + + return ret; + +bad: + iommu_free_ctx(iommu, ctx); +bad_no_ctx: + if (printk_ratelimit()) + WARN_ON(1); + return DMA_ERROR_CODE; +} + +static void strbuf_flush(struct strbuf *strbuf, struct iommu *iommu, + u32 vaddr, unsigned long ctx, unsigned long npages, + enum dma_data_direction direction) +{ + int limit; + + if (strbuf->strbuf_ctxflush && + iommu->iommu_ctxflush) { + unsigned long matchreg, flushreg; + u64 val; + + flushreg = strbuf->strbuf_ctxflush; + matchreg = STC_CTXMATCH_ADDR(strbuf, ctx); + + iommu_write(flushreg, ctx); + val = iommu_read(matchreg); + val &= 0xffff; + if (!val) + goto do_flush_sync; + + while (val) { + if (val & 0x1) + iommu_write(flushreg, ctx); + val >>= 1; + } + val = iommu_read(matchreg); + if (unlikely(val)) { + printk(KERN_WARNING "strbuf_flush: ctx flush " + "timeout matchreg[%lx] ctx[%lx]\n", + val, ctx); + goto do_page_flush; + } + } else { + unsigned long i; + + do_page_flush: + for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE) + iommu_write(strbuf->strbuf_pflush, vaddr); + } + +do_flush_sync: + /* If the device could not have possibly put dirty data into + * the streaming cache, no flush-flag synchronization needs + * to be performed. + */ + if (direction == DMA_TO_DEVICE) + return; + + STC_FLUSHFLAG_INIT(strbuf); + iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); + (void) iommu_read(iommu->write_complete_reg); + + limit = 100000; + while (!STC_FLUSHFLAG_SET(strbuf)) { + limit--; + if (!limit) + break; + udelay(1); + rmb(); + } + if (!limit) + printk(KERN_WARNING "strbuf_flush: flushflag timeout " + "vaddr[%08x] ctx[%lx] npages[%ld]\n", + vaddr, ctx, npages); +} + +static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr, + size_t sz, enum dma_data_direction direction) +{ + struct iommu *iommu; + struct strbuf *strbuf; + iopte_t *base; + unsigned long flags, npages, ctx, i; + + if (unlikely(direction == DMA_NONE)) { + if (printk_ratelimit()) + WARN_ON(1); + return; + } + + iommu = dev->archdata.iommu; + strbuf = dev->archdata.stc; + + npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); + npages >>= IO_PAGE_SHIFT; + base = iommu->page_table + + ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + bus_addr &= IO_PAGE_MASK; + + spin_lock_irqsave(&iommu->lock, flags); + + /* Record the context, if any. */ + ctx = 0; + if (iommu->iommu_ctxflush) + ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; + + /* Step 1: Kick data out of streaming buffers if necessary. */ + if (strbuf->strbuf_enabled) + strbuf_flush(strbuf, iommu, bus_addr, ctx, + npages, direction); + + /* Step 2: Clear out TSB entries. */ + for (i = 0; i < npages; i++) + iopte_make_dummy(iommu, base + i); + + free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); + + iommu_free_ctx(iommu, ctx); + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +#define SG_ENT_PHYS_ADDRESS(SG) \ + (__pa(page_address((SG)->page)) + (SG)->offset) + +static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, + int nused, int nelems, + unsigned long iopte_protection) +{ + struct scatterlist *dma_sg = sg; + struct scatterlist *sg_end = sg + nelems; + int i; + + for (i = 0; i < nused; i++) { + unsigned long pteval = ~0UL; + u32 dma_npages; + + dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) + + dma_sg->dma_length + + ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT; + do { + unsigned long offset; + signed int len; + + /* If we are here, we know we have at least one + * more page to map. So walk forward until we + * hit a page crossing, and begin creating new + * mappings from that spot. + */ + for (;;) { + unsigned long tmp; + + tmp = SG_ENT_PHYS_ADDRESS(sg); + len = sg->length; + if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) { + pteval = tmp & IO_PAGE_MASK; + offset = tmp & (IO_PAGE_SIZE - 1UL); + break; + } + if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) { + pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK; + offset = 0UL; + len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); + break; + } + sg++; + } + + pteval = iopte_protection | (pteval & IOPTE_PAGE); + while (len > 0) { + *iopte++ = __iopte(pteval); + pteval += IO_PAGE_SIZE; + len -= (IO_PAGE_SIZE - offset); + offset = 0; + dma_npages--; + } + + pteval = (pteval & IOPTE_PAGE) + len; + sg++; + + /* Skip over any tail mappings we've fully mapped, + * adjusting pteval along the way. Stop when we + * detect a page crossing event. + */ + while (sg < sg_end && + (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && + (pteval == SG_ENT_PHYS_ADDRESS(sg)) && + ((pteval ^ + (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { + pteval += sg->length; + sg++; + } + if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) + pteval = ~0UL; + } while (dma_npages != 0); + dma_sg++; + } +} + +static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, + int nelems, enum dma_data_direction direction) +{ + struct iommu *iommu; + struct strbuf *strbuf; + unsigned long flags, ctx, npages, iopte_protection; + iopte_t *base; + u32 dma_base; + struct scatterlist *sgtmp; + int used; + + /* Fast path single entry scatterlists. */ + if (nelems == 1) { + sglist->dma_address = + dma_4u_map_single(dev, + (page_address(sglist->page) + + sglist->offset), + sglist->length, direction); + if (unlikely(sglist->dma_address == DMA_ERROR_CODE)) + return 0; + sglist->dma_length = sglist->length; + return 1; + } + + iommu = dev->archdata.iommu; + strbuf = dev->archdata.stc; + + if (unlikely(direction == DMA_NONE)) + goto bad_no_ctx; + + /* Step 1: Prepare scatter list. */ + + npages = prepare_sg(sglist, nelems); + + /* Step 2: Allocate a cluster and context, if necessary. */ + + spin_lock_irqsave(&iommu->lock, flags); + + base = alloc_npages(iommu, npages); + ctx = 0; + if (iommu->iommu_ctxflush) + ctx = iommu_alloc_ctx(iommu); + + spin_unlock_irqrestore(&iommu->lock, flags); + + if (base == NULL) + goto bad; + + dma_base = iommu->page_table_map_base + + ((base - iommu->page_table) << IO_PAGE_SHIFT); + + /* Step 3: Normalize DMA addresses. */ + used = nelems; + + sgtmp = sglist; + while (used && sgtmp->dma_length) { + sgtmp->dma_address += dma_base; + sgtmp++; + used--; + } + used = nelems - used; + + /* Step 4: Create the mappings. */ + if (strbuf->strbuf_enabled) + iopte_protection = IOPTE_STREAMING(ctx); + else + iopte_protection = IOPTE_CONSISTENT(ctx); + if (direction != DMA_TO_DEVICE) + iopte_protection |= IOPTE_WRITE; + + fill_sg(base, sglist, used, nelems, iopte_protection); + +#ifdef VERIFY_SG + verify_sglist(sglist, nelems, base, npages); +#endif + + return used; + +bad: + iommu_free_ctx(iommu, ctx); +bad_no_ctx: + if (printk_ratelimit()) + WARN_ON(1); + return 0; +} + +static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist, + int nelems, enum dma_data_direction direction) +{ + struct iommu *iommu; + struct strbuf *strbuf; + iopte_t *base; + unsigned long flags, ctx, i, npages; + u32 bus_addr; + + if (unlikely(direction == DMA_NONE)) { + if (printk_ratelimit()) + WARN_ON(1); + } + + iommu = dev->archdata.iommu; + strbuf = dev->archdata.stc; + + bus_addr = sglist->dma_address & IO_PAGE_MASK; + + for (i = 1; i < nelems; i++) + if (sglist[i].dma_length == 0) + break; + i--; + npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - + bus_addr) >> IO_PAGE_SHIFT; + + base = iommu->page_table + + ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + + spin_lock_irqsave(&iommu->lock, flags); + + /* Record the context, if any. */ + ctx = 0; + if (iommu->iommu_ctxflush) + ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; + + /* Step 1: Kick data out of streaming buffers if necessary. */ + if (strbuf->strbuf_enabled) + strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); + + /* Step 2: Clear out the TSB entries. */ + for (i = 0; i < npages; i++) + iopte_make_dummy(iommu, base + i); + + free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); + + iommu_free_ctx(iommu, ctx); + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +static void dma_4u_sync_single_for_cpu(struct device *dev, + dma_addr_t bus_addr, size_t sz, + enum dma_data_direction direction) +{ + struct iommu *iommu; + struct strbuf *strbuf; + unsigned long flags, ctx, npages; + + iommu = dev->archdata.iommu; + strbuf = dev->archdata.stc; + + if (!strbuf->strbuf_enabled) + return; + + spin_lock_irqsave(&iommu->lock, flags); + + npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); + npages >>= IO_PAGE_SHIFT; + bus_addr &= IO_PAGE_MASK; + + /* Step 1: Record the context, if any. */ + ctx = 0; + if (iommu->iommu_ctxflush && + strbuf->strbuf_ctxflush) { + iopte_t *iopte; + + iopte = iommu->page_table + + ((bus_addr - iommu->page_table_map_base)>>IO_PAGE_SHIFT); + ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; + } + + /* Step 2: Kick data out of streaming buffers. */ + strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +static void dma_4u_sync_sg_for_cpu(struct device *dev, + struct scatterlist *sglist, int nelems, + enum dma_data_direction direction) +{ + struct iommu *iommu; + struct strbuf *strbuf; + unsigned long flags, ctx, npages, i; + u32 bus_addr; + + iommu = dev->archdata.iommu; + strbuf = dev->archdata.stc; + + if (!strbuf->strbuf_enabled) + return; + + spin_lock_irqsave(&iommu->lock, flags); + + /* Step 1: Record the context, if any. */ + ctx = 0; + if (iommu->iommu_ctxflush && + strbuf->strbuf_ctxflush) { + iopte_t *iopte; + + iopte = iommu->page_table + + ((sglist[0].dma_address - iommu->page_table_map_base) >> IO_PAGE_SHIFT); + ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; + } + + /* Step 2: Kick data out of streaming buffers. */ + bus_addr = sglist[0].dma_address & IO_PAGE_MASK; + for(i = 1; i < nelems; i++) + if (!sglist[i].dma_length) + break; + i--; + npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) + - bus_addr) >> IO_PAGE_SHIFT; + strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); + + spin_unlock_irqrestore(&iommu->lock, flags); +} + +const struct dma_ops sun4u_dma_ops = { + .alloc_coherent = dma_4u_alloc_coherent, + .free_coherent = dma_4u_free_coherent, + .map_single = dma_4u_map_single, + .unmap_single = dma_4u_unmap_single, + .map_sg = dma_4u_map_sg, + .unmap_sg = dma_4u_unmap_sg, + .sync_single_for_cpu = dma_4u_sync_single_for_cpu, + .sync_sg_for_cpu = dma_4u_sync_sg_for_cpu, +}; + +const struct dma_ops *dma_ops = &sun4u_dma_ops; +EXPORT_SYMBOL(dma_ops); + +int dma_supported(struct device *dev, u64 device_mask) +{ + struct iommu *iommu = dev->archdata.iommu; + u64 dma_addr_mask = iommu->dma_addr_mask; + + if (device_mask >= (1UL << 32UL)) + return 0; + + if ((device_mask & dma_addr_mask) == dma_addr_mask) + return 1; + +#ifdef CONFIG_PCI + if (dev->bus == &pci_bus_type) + return pci_dma_supported(to_pci_dev(dev), device_mask); +#endif + + return 0; +} +EXPORT_SYMBOL(dma_supported); + +int dma_set_mask(struct device *dev, u64 dma_mask) +{ +#ifdef CONFIG_PCI + if (dev->bus == &pci_bus_type) + return pci_set_dma_mask(to_pci_dev(dev), dma_mask); +#endif + return -EINVAL; +} +EXPORT_SYMBOL(dma_set_mask); diff --git a/arch/sparc64/kernel/isa.c b/arch/sparc64/kernel/isa.c index 1a1043fcf97..0f19dce1c90 100644 --- a/arch/sparc64/kernel/isa.c +++ b/arch/sparc64/kernel/isa.c @@ -90,6 +90,8 @@ static void __init isa_fill_devices(struct sparc_isa_bridge *isa_br) sd = &isa_dev->ofdev.dev.archdata; sd->prom_node = dp; sd->op = &isa_dev->ofdev; + sd->iommu = isa_br->ofdev.dev.parent->archdata.iommu; + sd->stc = isa_br->ofdev.dev.parent->archdata.stc; isa_dev->ofdev.node = dp; isa_dev->ofdev.dev.parent = &isa_br->ofdev.dev; diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c index 77449a00575..3d93e9203ba 100644 --- a/arch/sparc64/kernel/pci.c +++ b/arch/sparc64/kernel/pci.c @@ -283,12 +283,6 @@ int __init pcic_present(void) return pci_controller_scan(pci_is_controller); } -const struct pci_iommu_ops *pci_iommu_ops; -EXPORT_SYMBOL(pci_iommu_ops); - -extern const struct pci_iommu_ops pci_sun4u_iommu_ops, - pci_sun4v_iommu_ops; - /* Find each controller in the system, attach and initialize * software state structure for each and link into the * pci_pbm_root. Setup the controller enough such @@ -296,11 +290,6 @@ extern const struct pci_iommu_ops pci_sun4u_iommu_ops, */ static void __init pci_controller_probe(void) { - if (tlb_type == hypervisor) - pci_iommu_ops = &pci_sun4v_iommu_ops; - else - pci_iommu_ops = &pci_sun4u_iommu_ops; - printk("PCI: Probing for controllers.\n"); pci_controller_scan(pci_controller_init); @@ -406,6 +395,10 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm, sd->op = of_find_device_by_node(node); sd->msi_num = 0xffffffff; + sd = &sd->op->dev.archdata; + sd->iommu = pbm->iommu; + sd->stc = &pbm->stc; + type = of_get_property(node, "device_type", NULL); if (type == NULL) type = ""; @@ -1226,4 +1219,51 @@ struct device_node *pci_device_to_OF_node(struct pci_dev *pdev) } EXPORT_SYMBOL(pci_device_to_OF_node); +static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit) +{ + struct pci_dev *ali_isa_bridge; + u8 val; + + /* ALI sound chips generate 31-bits of DMA, a special register + * determines what bit 31 is emitted as. + */ + ali_isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, + PCI_DEVICE_ID_AL_M1533, + NULL); + + pci_read_config_byte(ali_isa_bridge, 0x7e, &val); + if (set_bit) + val |= 0x01; + else + val &= ~0x01; + pci_write_config_byte(ali_isa_bridge, 0x7e, val); + pci_dev_put(ali_isa_bridge); +} + +int pci_dma_supported(struct pci_dev *pdev, u64 device_mask) +{ + u64 dma_addr_mask; + + if (pdev == NULL) { + dma_addr_mask = 0xffffffff; + } else { + struct iommu *iommu = pdev->dev.archdata.iommu; + + dma_addr_mask = iommu->dma_addr_mask; + + if (pdev->vendor == PCI_VENDOR_ID_AL && + pdev->device == PCI_DEVICE_ID_AL_M5451 && + device_mask == 0x7fffffff) { + ali_sound_dma_hack(pdev, + (dma_addr_mask & 0x80000000) != 0); + return 1; + } + } + + if (device_mask >= (1UL << 32UL)) + return 0; + + return (device_mask & dma_addr_mask) == dma_addr_mask; +} + #endif /* !(CONFIG_PCI) */ diff --git a/arch/sparc64/kernel/pci_fire.c b/arch/sparc64/kernel/pci_fire.c index 7f5d473901c..14d67fe21ab 100644 --- a/arch/sparc64/kernel/pci_fire.c +++ b/arch/sparc64/kernel/pci_fire.c @@ -39,12 +39,12 @@ static void pci_fire_scan_bus(struct pci_pbm_info *pbm) #define FIRE_IOMMU_FLUSH 0x40100UL #define FIRE_IOMMU_FLUSHINV 0x40108UL -static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm) +static int pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm) { struct iommu *iommu = pbm->iommu; u32 vdma[2], dma_mask; u64 control; - int tsbsize; + int tsbsize, err; /* No virtual-dma property on these guys, use largest size. */ vdma[0] = 0xc0000000; /* base */ @@ -68,7 +68,9 @@ static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm) */ fire_write(iommu->iommu_flushinv, ~(u64)0); - pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask); + err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask); + if (err) + return err; fire_write(iommu->iommu_tsbbase, __pa(iommu->page_table) | 0x7UL); @@ -78,6 +80,8 @@ static void pci_fire_pbm_iommu_init(struct pci_pbm_info *pbm) 0x00000002 /* Bypass enable */ | 0x00000001 /* Translation enable */); fire_write(iommu->iommu_control, control); + + return 0; } /* Based at pbm->controller_regs */ @@ -167,8 +171,8 @@ static void pci_fire_hw_init(struct pci_pbm_info *pbm) fire_write(pbm->pbm_regs + FIRE_PEC_IENAB, ~(u64)0); } -static void pci_fire_pbm_init(struct pci_controller_info *p, - struct device_node *dp, u32 portid) +static int pci_fire_pbm_init(struct pci_controller_info *p, + struct device_node *dp, u32 portid) { const struct linux_prom64_registers *regs; struct pci_pbm_info *pbm; @@ -203,7 +207,8 @@ static void pci_fire_pbm_init(struct pci_controller_info *p, pci_get_pbm_props(pbm); pci_fire_hw_init(pbm); - pci_fire_pbm_iommu_init(pbm); + + return pci_fire_pbm_iommu_init(pbm); } static inline int portid_compare(u32 x, u32 y) @@ -222,7 +227,8 @@ void fire_pci_init(struct device_node *dp, const char *model_name) for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { if (portid_compare(pbm->portid, portid)) { - pci_fire_pbm_init(pbm->parent, dp, portid); + if (pci_fire_pbm_init(pbm->parent, dp, portid)) + goto fatal_memory_error; return; } } @@ -250,7 +256,9 @@ void fire_pci_init(struct device_node *dp, const char *model_name) */ pci_memspace_mask = 0x7fffffffUL; - pci_fire_pbm_init(p, dp, portid); + if (pci_fire_pbm_init(p, dp, portid)) + goto fatal_memory_error; + return; fatal_memory_error: diff --git a/arch/sparc64/kernel/pci_iommu.c b/arch/sparc64/kernel/pci_iommu.c deleted file mode 100644 index 70d2364fdfe..00000000000 --- a/arch/sparc64/kernel/pci_iommu.c +++ /dev/null @@ -1,823 +0,0 @@ -/* pci_iommu.c: UltraSparc PCI controller IOM/STC support. - * - * Copyright (C) 1999, 2007 David S. Miller (davem@davemloft.net) - * Copyright (C) 1999, 2000 Jakub Jelinek (jakub@redhat.com) - */ - -#include -#include -#include -#include -#include - -#include - -#include "iommu_common.h" -#include "pci_impl.h" - -#define PCI_STC_CTXMATCH_ADDR(STC, CTX) \ - ((STC)->strbuf_ctxmatch_base + ((CTX) << 3)) - -/* Accessing IOMMU and Streaming Buffer registers. - * REG parameter is a physical address. All registers - * are 64-bits in size. - */ -#define pci_iommu_read(__reg) \ -({ u64 __ret; \ - __asm__ __volatile__("ldxa [%1] %2, %0" \ - : "=r" (__ret) \ - : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \ - : "memory"); \ - __ret; \ -}) -#define pci_iommu_write(__reg, __val) \ - __asm__ __volatile__("stxa %0, [%1] %2" \ - : /* no outputs */ \ - : "r" (__val), "r" (__reg), \ - "i" (ASI_PHYS_BYPASS_EC_E)) - -/* Must be invoked under the IOMMU lock. */ -static void __iommu_flushall(struct iommu *iommu) -{ - if (iommu->iommu_flushinv) { - pci_iommu_write(iommu->iommu_flushinv, ~(u64)0); - } else { - unsigned long tag; - int entry; - - tag = iommu->iommu_flush + (0xa580UL - 0x0210UL); - for (entry = 0; entry < 16; entry++) { - pci_iommu_write(tag, 0); - tag += 8; - } - - /* Ensure completion of previous PIO writes. */ - (void) pci_iommu_read(iommu->write_complete_reg); - } -} - -#define IOPTE_CONSISTENT(CTX) \ - (IOPTE_VALID | IOPTE_CACHE | \ - (((CTX) << 47) & IOPTE_CONTEXT)) - -#define IOPTE_STREAMING(CTX) \ - (IOPTE_CONSISTENT(CTX) | IOPTE_STBUF) - -/* Existing mappings are never marked invalid, instead they - * are pointed to a dummy page. - */ -#define IOPTE_IS_DUMMY(iommu, iopte) \ - ((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa) - -static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte) -{ - unsigned long val = iopte_val(*iopte); - - val &= ~IOPTE_PAGE; - val |= iommu->dummy_page_pa; - - iopte_val(*iopte) = val; -} - -/* Based largely upon the ppc64 iommu allocator. */ -static long pci_arena_alloc(struct iommu *iommu, unsigned long npages) -{ - struct iommu_arena *arena = &iommu->arena; - unsigned long n, i, start, end, limit; - int pass; - - limit = arena->limit; - start = arena->hint; - pass = 0; - -again: - n = find_next_zero_bit(arena->map, limit, start); - end = n + npages; - if (unlikely(end >= limit)) { - if (likely(pass < 1)) { - limit = start; - start = 0; - __iommu_flushall(iommu); - pass++; - goto again; - } else { - /* Scanned the whole thing, give up. */ - return -1; - } - } - - for (i = n; i < end; i++) { - if (test_bit(i, arena->map)) { - start = i + 1; - goto again; - } - } - - for (i = n; i < end; i++) - __set_bit(i, arena->map); - - arena->hint = end; - - return n; -} - -static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages) -{ - unsigned long i; - - for (i = base; i < (base + npages); i++) - __clear_bit(i, arena->map); -} - -void pci_iommu_table_init(struct iommu *iommu, int tsbsize, u32 dma_offset, u32 dma_addr_mask) -{ - unsigned long i, tsbbase, order, sz, num_tsb_entries; - - num_tsb_entries = tsbsize / sizeof(iopte_t); - - /* Setup initial software IOMMU state. */ - spin_lock_init(&iommu->lock); - iommu->ctx_lowest_free = 1; - iommu->page_table_map_base = dma_offset; - iommu->dma_addr_mask = dma_addr_mask; - - /* Allocate and initialize the free area map. */ - sz = num_tsb_entries / 8; - sz = (sz + 7UL) & ~7UL; - iommu->arena.map = kzalloc(sz, GFP_KERNEL); - if (!iommu->arena.map) { - prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); - prom_halt(); - } - iommu->arena.limit = num_tsb_entries; - - /* Allocate and initialize the dummy page which we - * set inactive IO PTEs to point to. - */ - iommu->dummy_page = __get_free_pages(GFP_KERNEL, 0); - if (!iommu->dummy_page) { - prom_printf("PCI_IOMMU: Error, gfp(dummy_page) failed.\n"); - prom_halt(); - } - memset((void *)iommu->dummy_page, 0, PAGE_SIZE); - iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page); - - /* Now allocate and setup the IOMMU page table itself. */ - order = get_order(tsbsize); - tsbbase = __get_free_pages(GFP_KERNEL, order); - if (!tsbbase) { - prom_printf("PCI_IOMMU: Error, gfp(tsb) failed.\n"); - prom_halt(); - } - iommu->page_table = (iopte_t *)tsbbase; - - for (i = 0; i < num_tsb_entries; i++) - iopte_make_dummy(iommu, &iommu->page_table[i]); -} - -static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages) -{ - long entry; - - entry = pci_arena_alloc(iommu, npages); - if (unlikely(entry < 0)) - return NULL; - - return iommu->page_table + entry; -} - -static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages) -{ - pci_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages); -} - -static int iommu_alloc_ctx(struct iommu *iommu) -{ - int lowest = iommu->ctx_lowest_free; - int sz = IOMMU_NUM_CTXS - lowest; - int n = find_next_zero_bit(iommu->ctx_bitmap, sz, lowest); - - if (unlikely(n == sz)) { - n = find_next_zero_bit(iommu->ctx_bitmap, lowest, 1); - if (unlikely(n == lowest)) { - printk(KERN_WARNING "IOMMU: Ran out of contexts.\n"); - n = 0; - } - } - if (n) - __set_bit(n, iommu->ctx_bitmap); - - return n; -} - -static inline void iommu_free_ctx(struct iommu *iommu, int ctx) -{ - if (likely(ctx)) { - __clear_bit(ctx, iommu->ctx_bitmap); - if (ctx < iommu->ctx_lowest_free) - iommu->ctx_lowest_free = ctx; - } -} - -/* Allocate and map kernel buffer of size SIZE using consistent mode - * DMA for PCI device PDEV. Return non-NULL cpu-side address if - * successful and set *DMA_ADDRP to the PCI side dma address. - */ -static void *pci_4u_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) -{ - struct iommu *iommu; - iopte_t *iopte; - unsigned long flags, order, first_page; - void *ret; - int npages; - - size = IO_PAGE_ALIGN(size); - order = get_order(size); - if (order >= 10) - return NULL; - - first_page = __get_free_pages(gfp, order); - if (first_page == 0UL) - return NULL; - memset((char *)first_page, 0, PAGE_SIZE << order); - - iommu = pdev->dev.archdata.iommu; - - spin_lock_irqsave(&iommu->lock, flags); - iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT); - spin_unlock_irqrestore(&iommu->lock, flags); - - if (unlikely(iopte == NULL)) { - free_pages(first_page, order); - return NULL; - } - - *dma_addrp = (iommu->page_table_map_base + - ((iopte - iommu->page_table) << IO_PAGE_SHIFT)); - ret = (void *) first_page; - npages = size >> IO_PAGE_SHIFT; - first_page = __pa(first_page); - while (npages--) { - iopte_val(*iopte) = (IOPTE_CONSISTENT(0UL) | - IOPTE_WRITE | - (first_page & IOPTE_PAGE)); - iopte++; - first_page += IO_PAGE_SIZE; - } - - return ret; -} - -/* Free and unmap a consistent DMA translation. */ -static void pci_4u_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) -{ - struct iommu *iommu; - iopte_t *iopte; - unsigned long flags, order, npages; - - npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; - iommu = pdev->dev.archdata.iommu; - iopte = iommu->page_table + - ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); - - spin_lock_irqsave(&iommu->lock, flags); - - free_npages(iommu, dvma - iommu->page_table_map_base, npages); - - spin_unlock_irqrestore(&iommu->lock, flags); - - order = get_order(size); - if (order < 10) - free_pages((unsigned long)cpu, order); -} - -/* Map a single buffer at PTR of SZ bytes for PCI DMA - * in streaming mode. - */ -static dma_addr_t pci_4u_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) -{ - struct iommu *iommu; - struct strbuf *strbuf; - iopte_t *base; - unsigned long flags, npages, oaddr; - unsigned long i, base_paddr, ctx; - u32 bus_addr, ret; - unsigned long iopte_protection; - - iommu = pdev->dev.archdata.iommu; - strbuf = pdev->dev.archdata.stc; - - if (unlikely(direction == PCI_DMA_NONE)) - goto bad_no_ctx; - - oaddr = (unsigned long)ptr; - npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); - npages >>= IO_PAGE_SHIFT; - - spin_lock_irqsave(&iommu->lock, flags); - base = alloc_npages(iommu, npages); - ctx = 0; - if (iommu->iommu_ctxflush) - ctx = iommu_alloc_ctx(iommu); - spin_unlock_irqrestore(&iommu->lock, flags); - - if (unlikely(!base)) - goto bad; - - bus_addr = (iommu->page_table_map_base + - ((base - iommu->page_table) << IO_PAGE_SHIFT)); - ret = bus_addr | (oaddr & ~IO_PAGE_MASK); - base_paddr = __pa(oaddr & IO_PAGE_MASK); - if (strbuf->strbuf_enabled) - iopte_protection = IOPTE_STREAMING(ctx); - else - iopte_protection = IOPTE_CONSISTENT(ctx); - if (direction != PCI_DMA_TODEVICE) - iopte_protection |= IOPTE_WRITE; - - for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE) - iopte_val(*base) = iopte_protection | base_paddr; - - return ret; - -bad: - iommu_free_ctx(iommu, ctx); -bad_no_ctx: - if (printk_ratelimit()) - WARN_ON(1); - return PCI_DMA_ERROR_CODE; -} - -static void pci_strbuf_flush(struct strbuf *strbuf, struct iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction) -{ - int limit; - - if (strbuf->strbuf_ctxflush && - iommu->iommu_ctxflush) { - unsigned long matchreg, flushreg; - u64 val; - - flushreg = strbuf->strbuf_ctxflush; - matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); - - pci_iommu_write(flushreg, ctx); - val = pci_iommu_read(matchreg); - val &= 0xffff; - if (!val) - goto do_flush_sync; - - while (val) { - if (val & 0x1) - pci_iommu_write(flushreg, ctx); - val >>= 1; - } - val = pci_iommu_read(matchreg); - if (unlikely(val)) { - printk(KERN_WARNING "pci_strbuf_flush: ctx flush " - "timeout matchreg[%lx] ctx[%lx]\n", - val, ctx); - goto do_page_flush; - } - } else { - unsigned long i; - - do_page_flush: - for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE) - pci_iommu_write(strbuf->strbuf_pflush, vaddr); - } - -do_flush_sync: - /* If the device could not have possibly put dirty data into - * the streaming cache, no flush-flag synchronization needs - * to be performed. - */ - if (direction == PCI_DMA_TODEVICE) - return; - - PCI_STC_FLUSHFLAG_INIT(strbuf); - pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); - (void) pci_iommu_read(iommu->write_complete_reg); - - limit = 100000; - while (!PCI_STC_FLUSHFLAG_SET(strbuf)) { - limit--; - if (!limit) - break; - udelay(1); - rmb(); - } - if (!limit) - printk(KERN_WARNING "pci_strbuf_flush: flushflag timeout " - "vaddr[%08x] ctx[%lx] npages[%ld]\n", - vaddr, ctx, npages); -} - -/* Unmap a single streaming mode DMA translation. */ -static void pci_4u_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) -{ - struct iommu *iommu; - struct strbuf *strbuf; - iopte_t *base; - unsigned long flags, npages, ctx, i; - - if (unlikely(direction == PCI_DMA_NONE)) { - if (printk_ratelimit()) - WARN_ON(1); - return; - } - - iommu = pdev->dev.archdata.iommu; - strbuf = pdev->dev.archdata.stc; - - npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); - npages >>= IO_PAGE_SHIFT; - base = iommu->page_table + - ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); -#ifdef DEBUG_PCI_IOMMU - if (IOPTE_IS_DUMMY(iommu, base)) - printk("pci_unmap_single called on non-mapped region %08x,%08x from %016lx\n", - bus_addr, sz, __builtin_return_address(0)); -#endif - bus_addr &= IO_PAGE_MASK; - - spin_lock_irqsave(&iommu->lock, flags); - - /* Record the context, if any. */ - ctx = 0; - if (iommu->iommu_ctxflush) - ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; - - /* Step 1: Kick data out of streaming buffers if necessary. */ - if (strbuf->strbuf_enabled) - pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, - npages, direction); - - /* Step 2: Clear out TSB entries. */ - for (i = 0; i < npages; i++) - iopte_make_dummy(iommu, base + i); - - free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); - - iommu_free_ctx(iommu, ctx); - - spin_unlock_irqrestore(&iommu->lock, flags); -} - -#define SG_ENT_PHYS_ADDRESS(SG) \ - (__pa(page_address((SG)->page)) + (SG)->offset) - -static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, - int nused, int nelems, unsigned long iopte_protection) -{ - struct scatterlist *dma_sg = sg; - struct scatterlist *sg_end = sg + nelems; - int i; - - for (i = 0; i < nused; i++) { - unsigned long pteval = ~0UL; - u32 dma_npages; - - dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) + - dma_sg->dma_length + - ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT; - do { - unsigned long offset; - signed int len; - - /* If we are here, we know we have at least one - * more page to map. So walk forward until we - * hit a page crossing, and begin creating new - * mappings from that spot. - */ - for (;;) { - unsigned long tmp; - - tmp = SG_ENT_PHYS_ADDRESS(sg); - len = sg->length; - if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) { - pteval = tmp & IO_PAGE_MASK; - offset = tmp & (IO_PAGE_SIZE - 1UL); - break; - } - if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) { - pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK; - offset = 0UL; - len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); - break; - } - sg++; - } - - pteval = iopte_protection | (pteval & IOPTE_PAGE); - while (len > 0) { - *iopte++ = __iopte(pteval); - pteval += IO_PAGE_SIZE; - len -= (IO_PAGE_SIZE - offset); - offset = 0; - dma_npages--; - } - - pteval = (pteval & IOPTE_PAGE) + len; - sg++; - - /* Skip over any tail mappings we've fully mapped, - * adjusting pteval along the way. Stop when we - * detect a page crossing event. - */ - while (sg < sg_end && - (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && - (pteval == SG_ENT_PHYS_ADDRESS(sg)) && - ((pteval ^ - (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { - pteval += sg->length; - sg++; - } - if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) - pteval = ~0UL; - } while (dma_npages != 0); - dma_sg++; - } -} - -/* Map a set of buffers described by SGLIST with NELEMS array - * elements in streaming mode for PCI DMA. - * When making changes here, inspect the assembly output. I was having - * hard time to keep this routine out of using stack slots for holding variables. - */ -static int pci_4u_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) -{ - struct iommu *iommu; - struct strbuf *strbuf; - unsigned long flags, ctx, npages, iopte_protection; - iopte_t *base; - u32 dma_base; - struct scatterlist *sgtmp; - int used; - - /* Fast path single entry scatterlists. */ - if (nelems == 1) { - sglist->dma_address = - pci_4u_map_single(pdev, - (page_address(sglist->page) + sglist->offset), - sglist->length, direction); - if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE)) - return 0; - sglist->dma_length = sglist->length; - return 1; - } - - iommu = pdev->dev.archdata.iommu; - strbuf = pdev->dev.archdata.stc; - - if (unlikely(direction == PCI_DMA_NONE)) - goto bad_no_ctx; - - /* Step 1: Prepare scatter list. */ - - npages = prepare_sg(sglist, nelems); - - /* Step 2: Allocate a cluster and context, if necessary. */ - - spin_lock_irqsave(&iommu->lock, flags); - - base = alloc_npages(iommu, npages); - ctx = 0; - if (iommu->iommu_ctxflush) - ctx = iommu_alloc_ctx(iommu); - - spin_unlock_irqrestore(&iommu->lock, flags); - - if (base == NULL) - goto bad; - - dma_base = iommu->page_table_map_base + - ((base - iommu->page_table) << IO_PAGE_SHIFT); - - /* Step 3: Normalize DMA addresses. */ - used = nelems; - - sgtmp = sglist; - while (used && sgtmp->dma_length) { - sgtmp->dma_address += dma_base; - sgtmp++; - used--; - } - used = nelems - used; - - /* Step 4: Create the mappings. */ - if (strbuf->strbuf_enabled) - iopte_protection = IOPTE_STREAMING(ctx); - else - iopte_protection = IOPTE_CONSISTENT(ctx); - if (direction != PCI_DMA_TODEVICE) - iopte_protection |= IOPTE_WRITE; - - fill_sg(base, sglist, used, nelems, iopte_protection); - -#ifdef VERIFY_SG - verify_sglist(sglist, nelems, base, npages); -#endif - - return used; - -bad: - iommu_free_ctx(iommu, ctx); -bad_no_ctx: - if (printk_ratelimit()) - WARN_ON(1); - return 0; -} - -/* Unmap a set of streaming mode DMA translations. */ -static void pci_4u_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) -{ - struct iommu *iommu; - struct strbuf *strbuf; - iopte_t *base; - unsigned long flags, ctx, i, npages; - u32 bus_addr; - - if (unlikely(direction == PCI_DMA_NONE)) { - if (printk_ratelimit()) - WARN_ON(1); - } - - iommu = pdev->dev.archdata.iommu; - strbuf = pdev->dev.archdata.stc; - - bus_addr = sglist->dma_address & IO_PAGE_MASK; - - for (i = 1; i < nelems; i++) - if (sglist[i].dma_length == 0) - break; - i--; - npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - - bus_addr) >> IO_PAGE_SHIFT; - - base = iommu->page_table + - ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); - -#ifdef DEBUG_PCI_IOMMU - if (IOPTE_IS_DUMMY(iommu, base)) - printk("pci_unmap_sg called on non-mapped region %016lx,%d from %016lx\n", sglist->dma_address, nelems, __builtin_return_address(0)); -#endif - - spin_lock_irqsave(&iommu->lock, flags); - - /* Record the context, if any. */ - ctx = 0; - if (iommu->iommu_ctxflush) - ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL; - - /* Step 1: Kick data out of streaming buffers if necessary. */ - if (strbuf->strbuf_enabled) - pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); - - /* Step 2: Clear out the TSB entries. */ - for (i = 0; i < npages; i++) - iopte_make_dummy(iommu, base + i); - - free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); - - iommu_free_ctx(iommu, ctx); - - spin_unlock_irqrestore(&iommu->lock, flags); -} - -/* Make physical memory consistent for a single - * streaming mode DMA translation after a transfer. - */ -static void pci_4u_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) -{ - struct iommu *iommu; - struct strbuf *strbuf; - unsigned long flags, ctx, npages; - - iommu = pdev->dev.archdata.iommu; - strbuf = pdev->dev.archdata.stc; - - if (!strbuf->strbuf_enabled) - return; - - spin_lock_irqsave(&iommu->lock, flags); - - npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); - npages >>= IO_PAGE_SHIFT; - bus_addr &= IO_PAGE_MASK; - - /* Step 1: Record the context, if any. */ - ctx = 0; - if (iommu->iommu_ctxflush && - strbuf->strbuf_ctxflush) { - iopte_t *iopte; - - iopte = iommu->page_table + - ((bus_addr - iommu->page_table_map_base)>>IO_PAGE_SHIFT); - ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; - } - - /* Step 2: Kick data out of streaming buffers. */ - pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); - - spin_unlock_irqrestore(&iommu->lock, flags); -} - -/* Make physical memory consistent for a set of streaming - * mode DMA translations after a transfer. - */ -static void pci_4u_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) -{ - struct iommu *iommu; - struct strbuf *strbuf; - unsigned long flags, ctx, npages, i; - u32 bus_addr; - - iommu = pdev->dev.archdata.iommu; - strbuf = pdev->dev.archdata.stc; - - if (!strbuf->strbuf_enabled) - return; - - spin_lock_irqsave(&iommu->lock, flags); - - /* Step 1: Record the context, if any. */ - ctx = 0; - if (iommu->iommu_ctxflush && - strbuf->strbuf_ctxflush) { - iopte_t *iopte; - - iopte = iommu->page_table + - ((sglist[0].dma_address - iommu->page_table_map_base) >> IO_PAGE_SHIFT); - ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL; - } - - /* Step 2: Kick data out of streaming buffers. */ - bus_addr = sglist[0].dma_address & IO_PAGE_MASK; - for(i = 1; i < nelems; i++) - if (!sglist[i].dma_length) - break; - i--; - npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - - bus_addr) >> IO_PAGE_SHIFT; - pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction); - - spin_unlock_irqrestore(&iommu->lock, flags); -} - -const struct pci_iommu_ops pci_sun4u_iommu_ops = { - .alloc_consistent = pci_4u_alloc_consistent, - .free_consistent = pci_4u_free_consistent, - .map_single = pci_4u_map_single, - .unmap_single = pci_4u_unmap_single, - .map_sg = pci_4u_map_sg, - .unmap_sg = pci_4u_unmap_sg, - .dma_sync_single_for_cpu = pci_4u_dma_sync_single_for_cpu, - .dma_sync_sg_for_cpu = pci_4u_dma_sync_sg_for_cpu, -}; - -static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit) -{ - struct pci_dev *ali_isa_bridge; - u8 val; - - /* ALI sound chips generate 31-bits of DMA, a special register - * determines what bit 31 is emitted as. - */ - ali_isa_bridge = pci_get_device(PCI_VENDOR_ID_AL, - PCI_DEVICE_ID_AL_M1533, - NULL); - - pci_read_config_byte(ali_isa_bridge, 0x7e, &val); - if (set_bit) - val |= 0x01; - else - val &= ~0x01; - pci_write_config_byte(ali_isa_bridge, 0x7e, val); - pci_dev_put(ali_isa_bridge); -} - -int pci_dma_supported(struct pci_dev *pdev, u64 device_mask) -{ - u64 dma_addr_mask; - - if (pdev == NULL) { - dma_addr_mask = 0xffffffff; - } else { - struct iommu *iommu = pdev->dev.archdata.iommu; - - dma_addr_mask = iommu->dma_addr_mask; - - if (pdev->vendor == PCI_VENDOR_ID_AL && - pdev->device == PCI_DEVICE_ID_AL_M5451 && - device_mask == 0x7fffffff) { - ali_sound_dma_hack(pdev, - (dma_addr_mask & 0x80000000) != 0); - return 1; - } - } - - if (device_mask >= (1UL << 32UL)) - return 0; - - return (device_mask & dma_addr_mask) == dma_addr_mask; -} diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 598393a2df1..b6b4cfea5b5 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -813,16 +813,19 @@ static void psycho_scan_bus(struct pci_pbm_info *pbm) psycho_register_error_handlers(pbm); } -static void psycho_iommu_init(struct pci_pbm_info *pbm) +static int psycho_iommu_init(struct pci_pbm_info *pbm) { struct iommu *iommu = pbm->iommu; unsigned long i; u64 control; + int err; /* Register addresses. */ iommu->iommu_control = pbm->controller_regs + PSYCHO_IOMMU_CONTROL; iommu->iommu_tsbbase = pbm->controller_regs + PSYCHO_IOMMU_TSBBASE; iommu->iommu_flush = pbm->controller_regs + PSYCHO_IOMMU_FLUSH; + iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL); + /* PSYCHO's IOMMU lacks ctx flushing. */ iommu->iommu_ctxflush = 0; @@ -845,7 +848,9 @@ static void psycho_iommu_init(struct pci_pbm_info *pbm) /* Leave diag mode enabled for full-flushing done * in pci_iommu.c */ - pci_iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff); + err = iommu_table_init(iommu, IO_TSB_SIZE, 0xc0000000, 0xffffffff); + if (err) + return err; psycho_write(pbm->controller_regs + PSYCHO_IOMMU_TSBBASE, __pa(iommu->page_table)); @@ -858,6 +863,8 @@ static void psycho_iommu_init(struct pci_pbm_info *pbm) /* If necessary, hook us up for starfire IRQ translations. */ if (this_is_starfire) starfire_hookup(pbm->portid); + + return 0; } #define PSYCHO_IRQ_RETRY 0x1a00UL @@ -1031,15 +1038,12 @@ void psycho_init(struct device_node *dp, char *model_name) } p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); - if (!p) { - prom_printf("PSYCHO: Fatal memory allocation error.\n"); - prom_halt(); - } + if (!p) + goto fatal_memory_error; iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); - if (!iommu) { - prom_printf("PSYCHO: Fatal memory allocation error.\n"); - prom_halt(); - } + if (!iommu) + goto fatal_memory_error; + p->pbm_A.iommu = p->pbm_B.iommu = iommu; p->pbm_A.portid = upa_portid; @@ -1062,8 +1066,14 @@ void psycho_init(struct device_node *dp, char *model_name) psycho_controller_hwinit(&p->pbm_A); - psycho_iommu_init(&p->pbm_A); + if (psycho_iommu_init(&p->pbm_A)) + goto fatal_memory_error; is_pbm_a = ((pr_regs[0].phys_addr & 0x6000) == 0x2000); psycho_pbm_init(p, dp, is_pbm_a); + return; + +fatal_memory_error: + prom_printf("PSYCHO: Fatal memory allocation error.\n"); + prom_halt(); } diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 22e1be5c748..fba67c3d880 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -672,18 +672,20 @@ static void sabre_scan_bus(struct pci_pbm_info *pbm) sabre_register_error_handlers(pbm); } -static void sabre_iommu_init(struct pci_pbm_info *pbm, - int tsbsize, unsigned long dvma_offset, - u32 dma_mask) +static int sabre_iommu_init(struct pci_pbm_info *pbm, + int tsbsize, unsigned long dvma_offset, + u32 dma_mask) { struct iommu *iommu = pbm->iommu; unsigned long i; u64 control; + int err; /* Register addresses. */ iommu->iommu_control = pbm->controller_regs + SABRE_IOMMU_CONTROL; iommu->iommu_tsbbase = pbm->controller_regs + SABRE_IOMMU_TSBBASE; iommu->iommu_flush = pbm->controller_regs + SABRE_IOMMU_FLUSH; + iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL); iommu->write_complete_reg = pbm->controller_regs + SABRE_WRSYNC; /* Sabre's IOMMU lacks ctx flushing. */ iommu->iommu_ctxflush = 0; @@ -701,7 +703,10 @@ static void sabre_iommu_init(struct pci_pbm_info *pbm, /* Leave diag mode enabled for full-flushing done * in pci_iommu.c */ - pci_iommu_table_init(iommu, tsbsize * 1024 * 8, dvma_offset, dma_mask); + err = iommu_table_init(iommu, tsbsize * 1024 * 8, + dvma_offset, dma_mask); + if (err) + return err; sabre_write(pbm->controller_regs + SABRE_IOMMU_TSBBASE, __pa(iommu->page_table)); @@ -722,6 +727,8 @@ static void sabre_iommu_init(struct pci_pbm_info *pbm, break; } sabre_write(pbm->controller_regs + SABRE_IOMMU_CONTROL, control); + + return 0; } static void sabre_pbm_init(struct pci_controller_info *p, struct pci_pbm_info *pbm, struct device_node *dp) @@ -775,16 +782,12 @@ void sabre_init(struct device_node *dp, char *model_name) } p = kzalloc(sizeof(*p), GFP_ATOMIC); - if (!p) { - prom_printf("SABRE: Error, kmalloc(pci_controller_info) failed.\n"); - prom_halt(); - } + if (!p) + goto fatal_memory_error; iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC); - if (!iommu) { - prom_printf("SABRE: Error, kmalloc(pci_iommu) failed.\n"); - prom_halt(); - } + if (!iommu) + goto fatal_memory_error; pbm = &p->pbm_A; pbm->iommu = iommu; @@ -847,10 +850,16 @@ void sabre_init(struct device_node *dp, char *model_name) prom_halt(); } - sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask); + if (sabre_iommu_init(pbm, tsbsize, vdma[0], dma_mask)) + goto fatal_memory_error; /* * Look for APB underneath. */ sabre_pbm_init(p, pbm, dp); + return; + +fatal_memory_error: + prom_printf("SABRE: Fatal memory allocation error.\n"); + prom_halt(); } diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index ae76898bbe2..3c30bfa1f3a 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -1148,14 +1148,14 @@ static void schizo_pbm_strbuf_init(struct pci_pbm_info *pbm) #define SCHIZO_IOMMU_FLUSH (0x00210UL) #define SCHIZO_IOMMU_CTXFLUSH (0x00218UL) -static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) +static int schizo_pbm_iommu_init(struct pci_pbm_info *pbm) { struct iommu *iommu = pbm->iommu; unsigned long i, tagbase, database; struct property *prop; u32 vdma[2], dma_mask; + int tsbsize, err; u64 control; - int tsbsize; prop = of_find_property(pbm->prom_node, "virtual-dma", NULL); if (prop) { @@ -1195,6 +1195,7 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL; iommu->iommu_tsbbase = pbm->pbm_regs + SCHIZO_IOMMU_TSBBASE; iommu->iommu_flush = pbm->pbm_regs + SCHIZO_IOMMU_FLUSH; + iommu->iommu_tags = iommu->iommu_flush + (0xa580UL - 0x0210UL); iommu->iommu_ctxflush = pbm->pbm_regs + SCHIZO_IOMMU_CTXFLUSH; /* We use the main control/status register of SCHIZO as the write @@ -1219,7 +1220,9 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) /* Leave diag mode enabled for full-flushing done * in pci_iommu.c */ - pci_iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask); + err = iommu_table_init(iommu, tsbsize * 8 * 1024, vdma[0], dma_mask); + if (err) + return err; schizo_write(iommu->iommu_tsbbase, __pa(iommu->page_table)); @@ -1236,6 +1239,8 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) control |= SCHIZO_IOMMU_CTRL_ENAB; schizo_write(iommu->iommu_control, control); + + return 0; } #define SCHIZO_PCI_IRQ_RETRY (0x1a00UL) @@ -1328,14 +1333,14 @@ static void schizo_pbm_hw_init(struct pci_pbm_info *pbm) } } -static void schizo_pbm_init(struct pci_controller_info *p, - struct device_node *dp, u32 portid, - int chip_type) +static int schizo_pbm_init(struct pci_controller_info *p, + struct device_node *dp, u32 portid, + int chip_type) { const struct linux_prom64_registers *regs; struct pci_pbm_info *pbm; const char *chipset_name; - int is_pbm_a; + int is_pbm_a, err; switch (chip_type) { case PBM_CHIP_TYPE_TOMATILLO: @@ -1406,8 +1411,13 @@ static void schizo_pbm_init(struct pci_controller_info *p, pci_get_pbm_props(pbm); - schizo_pbm_iommu_init(pbm); + err = schizo_pbm_iommu_init(pbm); + if (err) + return err; + schizo_pbm_strbuf_init(pbm); + + return 0; } static inline int portid_compare(u32 x, u32 y, int chip_type) @@ -1431,34 +1441,38 @@ static void __schizo_init(struct device_node *dp, char *model_name, int chip_typ for (pbm = pci_pbm_root; pbm; pbm = pbm->next) { if (portid_compare(pbm->portid, portid, chip_type)) { - schizo_pbm_init(pbm->parent, dp, portid, chip_type); + if (schizo_pbm_init(pbm->parent, dp, + portid, chip_type)) + goto fatal_memory_error; return; } } p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); if (!p) - goto memfail; + goto fatal_memory_error; iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); if (!iommu) - goto memfail; + goto fatal_memory_error; p->pbm_A.iommu = iommu; iommu = kzalloc(sizeof(struct iommu), GFP_ATOMIC); if (!iommu) - goto memfail; + goto fatal_memory_error; p->pbm_B.iommu = iommu; /* Like PSYCHO we have a 2GB aligned area for memory space. */ pci_memspace_mask = 0x7fffffffUL; - schizo_pbm_init(p, dp, portid, chip_type); + if (schizo_pbm_init(p, dp, portid, chip_type)) + goto fatal_memory_error; + return; -memfail: +fatal_memory_error: prom_printf("SCHIZO: Fatal memory allocation error.\n"); prom_halt(); } diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 639cf06ca37..466f4aa8fc8 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -33,30 +33,30 @@ static unsigned long vpci_minor = 1; #define PGLIST_NENTS (PAGE_SIZE / sizeof(u64)) struct iommu_batch { - struct pci_dev *pdev; /* Device mapping is for. */ + struct device *dev; /* Device mapping is for. */ unsigned long prot; /* IOMMU page protections */ unsigned long entry; /* Index into IOTSB. */ u64 *pglist; /* List of physical pages */ unsigned long npages; /* Number of pages in list. */ }; -static DEFINE_PER_CPU(struct iommu_batch, pci_iommu_batch); +static DEFINE_PER_CPU(struct iommu_batch, iommu_batch); /* Interrupts must be disabled. */ -static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long prot, unsigned long entry) +static inline void iommu_batch_start(struct device *dev, unsigned long prot, unsigned long entry) { - struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch); + struct iommu_batch *p = &__get_cpu_var(iommu_batch); - p->pdev = pdev; + p->dev = dev; p->prot = prot; p->entry = entry; p->npages = 0; } /* Interrupts must be disabled. */ -static long pci_iommu_batch_flush(struct iommu_batch *p) +static long iommu_batch_flush(struct iommu_batch *p) { - struct pci_pbm_info *pbm = p->pdev->dev.archdata.host_controller; + struct pci_pbm_info *pbm = p->dev->archdata.host_controller; unsigned long devhandle = pbm->devhandle; unsigned long prot = p->prot; unsigned long entry = p->entry; @@ -70,7 +70,7 @@ static long pci_iommu_batch_flush(struct iommu_batch *p) npages, prot, __pa(pglist)); if (unlikely(num < 0)) { if (printk_ratelimit()) - printk("pci_iommu_batch_flush: IOMMU map of " + printk("iommu_batch_flush: IOMMU map of " "[%08lx:%08lx:%lx:%lx:%lx] failed with " "status %ld\n", devhandle, HV_PCI_TSBID(0, entry), @@ -90,30 +90,30 @@ static long pci_iommu_batch_flush(struct iommu_batch *p) } /* Interrupts must be disabled. */ -static inline long pci_iommu_batch_add(u64 phys_page) +static inline long iommu_batch_add(u64 phys_page) { - struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch); + struct iommu_batch *p = &__get_cpu_var(iommu_batch); BUG_ON(p->npages >= PGLIST_NENTS); p->pglist[p->npages++] = phys_page; if (p->npages == PGLIST_NENTS) - return pci_iommu_batch_flush(p); + return iommu_batch_flush(p); return 0; } /* Interrupts must be disabled. */ -static inline long pci_iommu_batch_end(void) +static inline long iommu_batch_end(void) { - struct iommu_batch *p = &__get_cpu_var(pci_iommu_batch); + struct iommu_batch *p = &__get_cpu_var(iommu_batch); BUG_ON(p->npages >= PGLIST_NENTS); - return pci_iommu_batch_flush(p); + return iommu_batch_flush(p); } -static long pci_arena_alloc(struct iommu_arena *arena, unsigned long npages) +static long arena_alloc(struct iommu_arena *arena, unsigned long npages) { unsigned long n, i, start, end, limit; int pass; @@ -152,7 +152,8 @@ again: return n; } -static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages) +static void arena_free(struct iommu_arena *arena, unsigned long base, + unsigned long npages) { unsigned long i; @@ -160,7 +161,8 @@ static void pci_arena_free(struct iommu_arena *arena, unsigned long base, unsign __clear_bit(i, arena->map); } -static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) +static void *dma_4v_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_addrp, gfp_t gfp) { struct iommu *iommu; unsigned long flags, order, first_page, npages, n; @@ -180,10 +182,10 @@ static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr memset((char *)first_page, 0, PAGE_SIZE << order); - iommu = pdev->dev.archdata.iommu; + iommu = dev->archdata.iommu; spin_lock_irqsave(&iommu->lock, flags); - entry = pci_arena_alloc(&iommu->arena, npages); + entry = arena_alloc(&iommu->arena, npages); spin_unlock_irqrestore(&iommu->lock, flags); if (unlikely(entry < 0L)) @@ -196,18 +198,18 @@ static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr local_irq_save(flags); - pci_iommu_batch_start(pdev, - (HV_PCI_MAP_ATTR_READ | - HV_PCI_MAP_ATTR_WRITE), - entry); + iommu_batch_start(dev, + (HV_PCI_MAP_ATTR_READ | + HV_PCI_MAP_ATTR_WRITE), + entry); for (n = 0; n < npages; n++) { - long err = pci_iommu_batch_add(first_page + (n * PAGE_SIZE)); + long err = iommu_batch_add(first_page + (n * PAGE_SIZE)); if (unlikely(err < 0L)) goto iommu_map_fail; } - if (unlikely(pci_iommu_batch_end() < 0L)) + if (unlikely(iommu_batch_end() < 0L)) goto iommu_map_fail; local_irq_restore(flags); @@ -217,7 +219,7 @@ static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr iommu_map_fail: /* Interrupts are disabled. */ spin_lock(&iommu->lock); - pci_arena_free(&iommu->arena, entry, npages); + arena_free(&iommu->arena, entry, npages); spin_unlock_irqrestore(&iommu->lock, flags); arena_alloc_fail: @@ -225,7 +227,8 @@ arena_alloc_fail: return NULL; } -static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) +static void dma_4v_free_coherent(struct device *dev, size_t size, void *cpu, + dma_addr_t dvma) { struct pci_pbm_info *pbm; struct iommu *iommu; @@ -233,14 +236,14 @@ static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, u32 devhandle; npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; - iommu = pdev->dev.archdata.iommu; - pbm = pdev->dev.archdata.host_controller; + iommu = dev->archdata.iommu; + pbm = dev->archdata.host_controller; devhandle = pbm->devhandle; entry = ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); spin_lock_irqsave(&iommu->lock, flags); - pci_arena_free(&iommu->arena, entry, npages); + arena_free(&iommu->arena, entry, npages); do { unsigned long num; @@ -258,7 +261,8 @@ static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, free_pages((unsigned long)cpu, order); } -static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) +static dma_addr_t dma_4v_map_single(struct device *dev, void *ptr, size_t sz, + enum dma_data_direction direction) { struct iommu *iommu; unsigned long flags, npages, oaddr; @@ -267,9 +271,9 @@ static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, unsigned long prot; long entry; - iommu = pdev->dev.archdata.iommu; + iommu = dev->archdata.iommu; - if (unlikely(direction == PCI_DMA_NONE)) + if (unlikely(direction == DMA_NONE)) goto bad; oaddr = (unsigned long)ptr; @@ -277,7 +281,7 @@ static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, npages >>= IO_PAGE_SHIFT; spin_lock_irqsave(&iommu->lock, flags); - entry = pci_arena_alloc(&iommu->arena, npages); + entry = arena_alloc(&iommu->arena, npages); spin_unlock_irqrestore(&iommu->lock, flags); if (unlikely(entry < 0L)) @@ -288,19 +292,19 @@ static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, ret = bus_addr | (oaddr & ~IO_PAGE_MASK); base_paddr = __pa(oaddr & IO_PAGE_MASK); prot = HV_PCI_MAP_ATTR_READ; - if (direction != PCI_DMA_TODEVICE) + if (direction != DMA_TO_DEVICE) prot |= HV_PCI_MAP_ATTR_WRITE; local_irq_save(flags); - pci_iommu_batch_start(pdev, prot, entry); + iommu_batch_start(dev, prot, entry); for (i = 0; i < npages; i++, base_paddr += IO_PAGE_SIZE) { - long err = pci_iommu_batch_add(base_paddr); + long err = iommu_batch_add(base_paddr); if (unlikely(err < 0L)) goto iommu_map_fail; } - if (unlikely(pci_iommu_batch_end() < 0L)) + if (unlikely(iommu_batch_end() < 0L)) goto iommu_map_fail; local_irq_restore(flags); @@ -310,18 +314,19 @@ static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, bad: if (printk_ratelimit()) WARN_ON(1); - return PCI_DMA_ERROR_CODE; + return DMA_ERROR_CODE; iommu_map_fail: /* Interrupts are disabled. */ spin_lock(&iommu->lock); - pci_arena_free(&iommu->arena, entry, npages); + arena_free(&iommu->arena, entry, npages); spin_unlock_irqrestore(&iommu->lock, flags); - return PCI_DMA_ERROR_CODE; + return DMA_ERROR_CODE; } -static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) +static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr, + size_t sz, enum dma_data_direction direction) { struct pci_pbm_info *pbm; struct iommu *iommu; @@ -329,14 +334,14 @@ static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_ long entry; u32 devhandle; - if (unlikely(direction == PCI_DMA_NONE)) { + if (unlikely(direction == DMA_NONE)) { if (printk_ratelimit()) WARN_ON(1); return; } - iommu = pdev->dev.archdata.iommu; - pbm = pdev->dev.archdata.host_controller; + iommu = dev->archdata.iommu; + pbm = dev->archdata.host_controller; devhandle = pbm->devhandle; npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); @@ -346,7 +351,7 @@ static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_ spin_lock_irqsave(&iommu->lock, flags); entry = (bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT; - pci_arena_free(&iommu->arena, entry, npages); + arena_free(&iommu->arena, entry, npages); do { unsigned long num; @@ -363,7 +368,7 @@ static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_ #define SG_ENT_PHYS_ADDRESS(SG) \ (__pa(page_address((SG)->page)) + (SG)->offset) -static inline long fill_sg(long entry, struct pci_dev *pdev, +static inline long fill_sg(long entry, struct device *dev, struct scatterlist *sg, int nused, int nelems, unsigned long prot) { @@ -374,7 +379,7 @@ static inline long fill_sg(long entry, struct pci_dev *pdev, local_irq_save(flags); - pci_iommu_batch_start(pdev, prot, entry); + iommu_batch_start(dev, prot, entry); for (i = 0; i < nused; i++) { unsigned long pteval = ~0UL; @@ -415,7 +420,7 @@ static inline long fill_sg(long entry, struct pci_dev *pdev, while (len > 0) { long err; - err = pci_iommu_batch_add(pteval); + err = iommu_batch_add(pteval); if (unlikely(err < 0L)) goto iommu_map_failed; @@ -446,7 +451,7 @@ static inline long fill_sg(long entry, struct pci_dev *pdev, dma_sg++; } - if (unlikely(pci_iommu_batch_end() < 0L)) + if (unlikely(iommu_batch_end() < 0L)) goto iommu_map_failed; local_irq_restore(flags); @@ -457,7 +462,8 @@ iommu_map_failed: return -1L; } -static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) +static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, + int nelems, enum dma_data_direction direction) { struct iommu *iommu; unsigned long flags, npages, prot; @@ -469,18 +475,19 @@ static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n /* Fast path single entry scatterlists. */ if (nelems == 1) { sglist->dma_address = - pci_4v_map_single(pdev, - (page_address(sglist->page) + sglist->offset), + dma_4v_map_single(dev, + (page_address(sglist->page) + + sglist->offset), sglist->length, direction); - if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE)) + if (unlikely(sglist->dma_address == DMA_ERROR_CODE)) return 0; sglist->dma_length = sglist->length; return 1; } - iommu = pdev->dev.archdata.iommu; + iommu = dev->archdata.iommu; - if (unlikely(direction == PCI_DMA_NONE)) + if (unlikely(direction == DMA_NONE)) goto bad; /* Step 1: Prepare scatter list. */ @@ -488,7 +495,7 @@ static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n /* Step 2: Allocate a cluster and context, if necessary. */ spin_lock_irqsave(&iommu->lock, flags); - entry = pci_arena_alloc(&iommu->arena, npages); + entry = arena_alloc(&iommu->arena, npages); spin_unlock_irqrestore(&iommu->lock, flags); if (unlikely(entry < 0L)) @@ -510,10 +517,10 @@ static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int n /* Step 4: Create the mappings. */ prot = HV_PCI_MAP_ATTR_READ; - if (direction != PCI_DMA_TODEVICE) + if (direction != DMA_TO_DEVICE) prot |= HV_PCI_MAP_ATTR_WRITE; - err = fill_sg(entry, pdev, sglist, used, nelems, prot); + err = fill_sg(entry, dev, sglist, used, nelems, prot); if (unlikely(err < 0L)) goto iommu_map_failed; @@ -526,13 +533,14 @@ bad: iommu_map_failed: spin_lock_irqsave(&iommu->lock, flags); - pci_arena_free(&iommu->arena, entry, npages); + arena_free(&iommu->arena, entry, npages); spin_unlock_irqrestore(&iommu->lock, flags); return 0; } -static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) +static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, + int nelems, enum dma_data_direction direction) { struct pci_pbm_info *pbm; struct iommu *iommu; @@ -540,13 +548,13 @@ static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in long entry; u32 devhandle, bus_addr; - if (unlikely(direction == PCI_DMA_NONE)) { + if (unlikely(direction == DMA_NONE)) { if (printk_ratelimit()) WARN_ON(1); } - iommu = pdev->dev.archdata.iommu; - pbm = pdev->dev.archdata.host_controller; + iommu = dev->archdata.iommu; + pbm = dev->archdata.host_controller; devhandle = pbm->devhandle; bus_addr = sglist->dma_address & IO_PAGE_MASK; @@ -562,7 +570,7 @@ static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in spin_lock_irqsave(&iommu->lock, flags); - pci_arena_free(&iommu->arena, entry, npages); + arena_free(&iommu->arena, entry, npages); do { unsigned long num; @@ -576,25 +584,29 @@ static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, in spin_unlock_irqrestore(&iommu->lock, flags); } -static void pci_4v_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) +static void dma_4v_sync_single_for_cpu(struct device *dev, + dma_addr_t bus_addr, size_t sz, + enum dma_data_direction direction) { /* Nothing to do... */ } -static void pci_4v_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) +static void dma_4v_sync_sg_for_cpu(struct device *dev, + struct scatterlist *sglist, int nelems, + enum dma_data_direction direction) { /* Nothing to do... */ } -const struct pci_iommu_ops pci_sun4v_iommu_ops = { - .alloc_consistent = pci_4v_alloc_consistent, - .free_consistent = pci_4v_free_consistent, - .map_single = pci_4v_map_single, - .unmap_single = pci_4v_unmap_single, - .map_sg = pci_4v_map_sg, - .unmap_sg = pci_4v_unmap_sg, - .dma_sync_single_for_cpu = pci_4v_dma_sync_single_for_cpu, - .dma_sync_sg_for_cpu = pci_4v_dma_sync_sg_for_cpu, +const struct dma_ops sun4v_dma_ops = { + .alloc_coherent = dma_4v_alloc_coherent, + .free_coherent = dma_4v_free_coherent, + .map_single = dma_4v_map_single, + .unmap_single = dma_4v_unmap_single, + .map_sg = dma_4v_map_sg, + .unmap_sg = dma_4v_unmap_sg, + .sync_single_for_cpu = dma_4v_sync_single_for_cpu, + .sync_sg_for_cpu = dma_4v_sync_sg_for_cpu, }; static void pci_sun4v_scan_bus(struct pci_pbm_info *pbm) @@ -1186,6 +1198,8 @@ void __init sun4v_pci_init(struct device_node *dp, char *model_name) } printk("SUN4V_PCI: Registered hvapi major[%lu] minor[%lu]\n", vpci_major, vpci_minor); + + dma_ops = &sun4v_dma_ops; } prop = of_find_property(dp, "reg", NULL); @@ -1206,7 +1220,7 @@ void __init sun4v_pci_init(struct device_node *dp, char *model_name) if (!page) goto fatal_memory_error; - per_cpu(pci_iommu_batch, i).pglist = (u64 *) page; + per_cpu(iommu_batch, i).pglist = (u64 *) page; } p = kzalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c index a1fd9bcc0b8..d1fb13ba02b 100644 --- a/arch/sparc64/kernel/sbus.c +++ b/arch/sparc64/kernel/sbus.c @@ -26,11 +26,6 @@ #define MAP_BASE ((u32)0xc0000000) -struct sbus_info { - struct iommu iommu; - struct strbuf strbuf; -}; - /* Offsets from iommu_regs */ #define SYSIO_IOMMUREG_BASE 0x2400UL #define IOMMU_CONTROL (0x2400UL - 0x2400UL) /* IOMMU control register */ @@ -44,19 +39,6 @@ struct sbus_info { #define IOMMU_DRAM_VALID (1UL << 30UL) -static void __iommu_flushall(struct iommu *iommu) -{ - unsigned long tag; - int entry; - - tag = iommu->iommu_control + (IOMMU_TAGDIAG - IOMMU_CONTROL); - for (entry = 0; entry < 16; entry++) { - upa_writeq(0, tag); - tag += 8UL; - } - upa_readq(iommu->write_complete_reg); -} - /* Offsets from strbuf_regs */ #define SYSIO_STRBUFREG_BASE 0x2800UL #define STRBUF_CONTROL (0x2800UL - 0x2800UL) /* Control */ @@ -69,511 +51,10 @@ static void __iommu_flushall(struct iommu *iommu) #define STRBUF_TAG_VALID 0x02UL -static void sbus_strbuf_flush(struct iommu *iommu, struct strbuf *strbuf, u32 base, unsigned long npages, int direction) -{ - unsigned long n; - int limit; - - n = npages; - while (n--) - upa_writeq(base + (n << IO_PAGE_SHIFT), strbuf->strbuf_pflush); - - /* If the device could not have possibly put dirty data into - * the streaming cache, no flush-flag synchronization needs - * to be performed. - */ - if (direction == SBUS_DMA_TODEVICE) - return; - - *(strbuf->strbuf_flushflag) = 0UL; - - /* Whoopee cushion! */ - upa_writeq(strbuf->strbuf_flushflag_pa, strbuf->strbuf_fsync); - upa_readq(iommu->write_complete_reg); - - limit = 100000; - while (*(strbuf->strbuf_flushflag) == 0UL) { - limit--; - if (!limit) - break; - udelay(1); - rmb(); - } - if (!limit) - printk(KERN_WARNING "sbus_strbuf_flush: flushflag timeout " - "vaddr[%08x] npages[%ld]\n", - base, npages); -} - -/* Based largely upon the ppc64 iommu allocator. */ -static long sbus_arena_alloc(struct iommu *iommu, unsigned long npages) -{ - struct iommu_arena *arena = &iommu->arena; - unsigned long n, i, start, end, limit; - int pass; - - limit = arena->limit; - start = arena->hint; - pass = 0; - -again: - n = find_next_zero_bit(arena->map, limit, start); - end = n + npages; - if (unlikely(end >= limit)) { - if (likely(pass < 1)) { - limit = start; - start = 0; - __iommu_flushall(iommu); - pass++; - goto again; - } else { - /* Scanned the whole thing, give up. */ - return -1; - } - } - - for (i = n; i < end; i++) { - if (test_bit(i, arena->map)) { - start = i + 1; - goto again; - } - } - - for (i = n; i < end; i++) - __set_bit(i, arena->map); - - arena->hint = end; - - return n; -} - -static void sbus_arena_free(struct iommu_arena *arena, unsigned long base, unsigned long npages) -{ - unsigned long i; - - for (i = base; i < (base + npages); i++) - __clear_bit(i, arena->map); -} - -static void sbus_iommu_table_init(struct iommu *iommu, unsigned int tsbsize) -{ - unsigned long tsbbase, order, sz, num_tsb_entries; - - num_tsb_entries = tsbsize / sizeof(iopte_t); - - /* Setup initial software IOMMU state. */ - spin_lock_init(&iommu->lock); - iommu->page_table_map_base = MAP_BASE; - - /* Allocate and initialize the free area map. */ - sz = num_tsb_entries / 8; - sz = (sz + 7UL) & ~7UL; - iommu->arena.map = kzalloc(sz, GFP_KERNEL); - if (!iommu->arena.map) { - prom_printf("SBUS_IOMMU: Error, kmalloc(arena.map) failed.\n"); - prom_halt(); - } - iommu->arena.limit = num_tsb_entries; - - /* Now allocate and setup the IOMMU page table itself. */ - order = get_order(tsbsize); - tsbbase = __get_free_pages(GFP_KERNEL, order); - if (!tsbbase) { - prom_printf("IOMMU: Error, gfp(tsb) failed.\n"); - prom_halt(); - } - iommu->page_table = (iopte_t *)tsbbase; - memset(iommu->page_table, 0, tsbsize); -} - -static inline iopte_t *alloc_npages(struct iommu *iommu, unsigned long npages) -{ - long entry; - - entry = sbus_arena_alloc(iommu, npages); - if (unlikely(entry < 0)) - return NULL; - - return iommu->page_table + entry; -} - -static inline void free_npages(struct iommu *iommu, dma_addr_t base, unsigned long npages) -{ - sbus_arena_free(&iommu->arena, base >> IO_PAGE_SHIFT, npages); -} - -void *sbus_alloc_consistent(struct sbus_dev *sdev, size_t size, dma_addr_t *dvma_addr) -{ - struct sbus_info *info; - struct iommu *iommu; - iopte_t *iopte; - unsigned long flags, order, first_page; - void *ret; - int npages; - - size = IO_PAGE_ALIGN(size); - order = get_order(size); - if (order >= 10) - return NULL; - - first_page = __get_free_pages(GFP_KERNEL|__GFP_COMP, order); - if (first_page == 0UL) - return NULL; - memset((char *)first_page, 0, PAGE_SIZE << order); - - info = sdev->bus->iommu; - iommu = &info->iommu; - - spin_lock_irqsave(&iommu->lock, flags); - iopte = alloc_npages(iommu, size >> IO_PAGE_SHIFT); - spin_unlock_irqrestore(&iommu->lock, flags); - - if (unlikely(iopte == NULL)) { - free_pages(first_page, order); - return NULL; - } - - *dvma_addr = (iommu->page_table_map_base + - ((iopte - iommu->page_table) << IO_PAGE_SHIFT)); - ret = (void *) first_page; - npages = size >> IO_PAGE_SHIFT; - first_page = __pa(first_page); - while (npages--) { - iopte_val(*iopte) = (IOPTE_VALID | IOPTE_CACHE | - IOPTE_WRITE | - (first_page & IOPTE_PAGE)); - iopte++; - first_page += IO_PAGE_SIZE; - } - - return ret; -} - -void sbus_free_consistent(struct sbus_dev *sdev, size_t size, void *cpu, dma_addr_t dvma) -{ - struct sbus_info *info; - struct iommu *iommu; - iopte_t *iopte; - unsigned long flags, order, npages; - - npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; - info = sdev->bus->iommu; - iommu = &info->iommu; - iopte = iommu->page_table + - ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); - - spin_lock_irqsave(&iommu->lock, flags); - - free_npages(iommu, dvma - iommu->page_table_map_base, npages); - - spin_unlock_irqrestore(&iommu->lock, flags); - - order = get_order(size); - if (order < 10) - free_pages((unsigned long)cpu, order); -} - -dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, size_t sz, int direction) -{ - struct sbus_info *info; - struct iommu *iommu; - iopte_t *base; - unsigned long flags, npages, oaddr; - unsigned long i, base_paddr; - u32 bus_addr, ret; - unsigned long iopte_protection; - - info = sdev->bus->iommu; - iommu = &info->iommu; - - if (unlikely(direction == SBUS_DMA_NONE)) - BUG(); - - oaddr = (unsigned long)ptr; - npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); - npages >>= IO_PAGE_SHIFT; - - spin_lock_irqsave(&iommu->lock, flags); - base = alloc_npages(iommu, npages); - spin_unlock_irqrestore(&iommu->lock, flags); - - if (unlikely(!base)) - BUG(); - - bus_addr = (iommu->page_table_map_base + - ((base - iommu->page_table) << IO_PAGE_SHIFT)); - ret = bus_addr | (oaddr & ~IO_PAGE_MASK); - base_paddr = __pa(oaddr & IO_PAGE_MASK); - - iopte_protection = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE; - if (direction != SBUS_DMA_TODEVICE) - iopte_protection |= IOPTE_WRITE; - - for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE) - iopte_val(*base) = iopte_protection | base_paddr; - - return ret; -} - -void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction) -{ - struct sbus_info *info = sdev->bus->iommu; - struct iommu *iommu = &info->iommu; - struct strbuf *strbuf = &info->strbuf; - iopte_t *base; - unsigned long flags, npages, i; - - if (unlikely(direction == SBUS_DMA_NONE)) - BUG(); - - npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); - npages >>= IO_PAGE_SHIFT; - base = iommu->page_table + - ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); - - bus_addr &= IO_PAGE_MASK; - - spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction); - for (i = 0; i < npages; i++) - iopte_val(base[i]) = 0UL; - free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); - spin_unlock_irqrestore(&iommu->lock, flags); -} - -#define SG_ENT_PHYS_ADDRESS(SG) \ - (__pa(page_address((SG)->page)) + (SG)->offset) - -static inline void fill_sg(iopte_t *iopte, struct scatterlist *sg, - int nused, int nelems, unsigned long iopte_protection) -{ - struct scatterlist *dma_sg = sg; - struct scatterlist *sg_end = sg + nelems; - int i; - - for (i = 0; i < nused; i++) { - unsigned long pteval = ~0UL; - u32 dma_npages; - - dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) + - dma_sg->dma_length + - ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT; - do { - unsigned long offset; - signed int len; - - /* If we are here, we know we have at least one - * more page to map. So walk forward until we - * hit a page crossing, and begin creating new - * mappings from that spot. - */ - for (;;) { - unsigned long tmp; - - tmp = SG_ENT_PHYS_ADDRESS(sg); - len = sg->length; - if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) { - pteval = tmp & IO_PAGE_MASK; - offset = tmp & (IO_PAGE_SIZE - 1UL); - break; - } - if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) { - pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK; - offset = 0UL; - len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); - break; - } - sg++; - } - - pteval = iopte_protection | (pteval & IOPTE_PAGE); - while (len > 0) { - *iopte++ = __iopte(pteval); - pteval += IO_PAGE_SIZE; - len -= (IO_PAGE_SIZE - offset); - offset = 0; - dma_npages--; - } - - pteval = (pteval & IOPTE_PAGE) + len; - sg++; - - /* Skip over any tail mappings we've fully mapped, - * adjusting pteval along the way. Stop when we - * detect a page crossing event. - */ - while (sg < sg_end && - (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && - (pteval == SG_ENT_PHYS_ADDRESS(sg)) && - ((pteval ^ - (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { - pteval += sg->length; - sg++; - } - if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) - pteval = ~0UL; - } while (dma_npages != 0); - dma_sg++; - } -} - -int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction) -{ - struct sbus_info *info; - struct iommu *iommu; - unsigned long flags, npages, iopte_protection; - iopte_t *base; - u32 dma_base; - struct scatterlist *sgtmp; - int used; - - /* Fast path single entry scatterlists. */ - if (nelems == 1) { - sglist->dma_address = - sbus_map_single(sdev, - (page_address(sglist->page) + sglist->offset), - sglist->length, direction); - sglist->dma_length = sglist->length; - return 1; - } - - info = sdev->bus->iommu; - iommu = &info->iommu; - - if (unlikely(direction == SBUS_DMA_NONE)) - BUG(); - - npages = prepare_sg(sglist, nelems); - - spin_lock_irqsave(&iommu->lock, flags); - base = alloc_npages(iommu, npages); - spin_unlock_irqrestore(&iommu->lock, flags); - - if (unlikely(base == NULL)) - BUG(); - - dma_base = iommu->page_table_map_base + - ((base - iommu->page_table) << IO_PAGE_SHIFT); - - /* Normalize DVMA addresses. */ - used = nelems; - - sgtmp = sglist; - while (used && sgtmp->dma_length) { - sgtmp->dma_address += dma_base; - sgtmp++; - used--; - } - used = nelems - used; - - iopte_protection = IOPTE_VALID | IOPTE_STBUF | IOPTE_CACHE; - if (direction != SBUS_DMA_TODEVICE) - iopte_protection |= IOPTE_WRITE; - - fill_sg(base, sglist, used, nelems, iopte_protection); - -#ifdef VERIFY_SG - verify_sglist(sglist, nelems, base, npages); -#endif - - return used; -} - -void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction) -{ - struct sbus_info *info; - struct iommu *iommu; - struct strbuf *strbuf; - iopte_t *base; - unsigned long flags, i, npages; - u32 bus_addr; - - if (unlikely(direction == SBUS_DMA_NONE)) - BUG(); - - info = sdev->bus->iommu; - iommu = &info->iommu; - strbuf = &info->strbuf; - - bus_addr = sglist->dma_address & IO_PAGE_MASK; - - for (i = 1; i < nelems; i++) - if (sglist[i].dma_length == 0) - break; - i--; - npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - - bus_addr) >> IO_PAGE_SHIFT; - - base = iommu->page_table + - ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); - - spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction); - for (i = 0; i < npages; i++) - iopte_val(base[i]) = 0UL; - free_npages(iommu, bus_addr - iommu->page_table_map_base, npages); - spin_unlock_irqrestore(&iommu->lock, flags); -} - -void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t bus_addr, size_t sz, int direction) -{ - struct sbus_info *info; - struct iommu *iommu; - struct strbuf *strbuf; - unsigned long flags, npages; - - info = sdev->bus->iommu; - iommu = &info->iommu; - strbuf = &info->strbuf; - - npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); - npages >>= IO_PAGE_SHIFT; - bus_addr &= IO_PAGE_MASK; - - spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction); - spin_unlock_irqrestore(&iommu->lock, flags); -} - -void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t base, size_t size, int direction) -{ -} - -void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sglist, int nelems, int direction) -{ - struct sbus_info *info; - struct iommu *iommu; - struct strbuf *strbuf; - unsigned long flags, npages, i; - u32 bus_addr; - - info = sdev->bus->iommu; - iommu = &info->iommu; - strbuf = &info->strbuf; - - bus_addr = sglist[0].dma_address & IO_PAGE_MASK; - for (i = 0; i < nelems; i++) { - if (!sglist[i].dma_length) - break; - } - i--; - npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - - bus_addr) >> IO_PAGE_SHIFT; - - spin_lock_irqsave(&iommu->lock, flags); - sbus_strbuf_flush(iommu, strbuf, bus_addr, npages, direction); - spin_unlock_irqrestore(&iommu->lock, flags); -} - -void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int direction) -{ -} - /* Enable 64-bit DVMA mode for the given device. */ void sbus_set_sbus64(struct sbus_dev *sdev, int bursts) { - struct sbus_info *info = sdev->bus->iommu; - struct iommu *iommu = &info->iommu; + struct iommu *iommu = sdev->ofdev.dev.archdata.iommu; int slot = sdev->slot; unsigned long cfg_reg; u64 val; @@ -713,8 +194,7 @@ static unsigned long sysio_imap_to_iclr(unsigned long imap) unsigned int sbus_build_irq(void *buscookie, unsigned int ino) { struct sbus_bus *sbus = (struct sbus_bus *)buscookie; - struct sbus_info *info = sbus->iommu; - struct iommu *iommu = &info->iommu; + struct iommu *iommu = sbus->ofdev.dev.archdata.iommu; unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; unsigned long imap, iclr; int sbus_level = 0; @@ -776,8 +256,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino) static irqreturn_t sysio_ue_handler(int irq, void *dev_id) { struct sbus_bus *sbus = dev_id; - struct sbus_info *info = sbus->iommu; - struct iommu *iommu = &info->iommu; + struct iommu *iommu = sbus->ofdev.dev.archdata.iommu; unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; unsigned long afsr_reg, afar_reg; unsigned long afsr, afar, error_bits; @@ -849,8 +328,7 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id) static irqreturn_t sysio_ce_handler(int irq, void *dev_id) { struct sbus_bus *sbus = dev_id; - struct sbus_info *info = sbus->iommu; - struct iommu *iommu = &info->iommu; + struct iommu *iommu = sbus->ofdev.dev.archdata.iommu; unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; unsigned long afsr_reg, afar_reg; unsigned long afsr, afar, error_bits; @@ -927,8 +405,7 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id) static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id) { struct sbus_bus *sbus = dev_id; - struct sbus_info *info = sbus->iommu; - struct iommu *iommu = &info->iommu; + struct iommu *iommu = sbus->ofdev.dev.archdata.iommu; unsigned long afsr_reg, afar_reg, reg_base; unsigned long afsr, afar, error_bits; int reported; @@ -995,8 +472,7 @@ static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id) static void __init sysio_register_error_handlers(struct sbus_bus *sbus) { - struct sbus_info *info = sbus->iommu; - struct iommu *iommu = &info->iommu; + struct iommu *iommu = sbus->ofdev.dev.archdata.iommu; unsigned long reg_base = iommu->write_complete_reg - 0x2000UL; unsigned int irq; u64 control; @@ -1041,7 +517,6 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) { const struct linux_prom64_registers *pr; struct device_node *dp; - struct sbus_info *info; struct iommu *iommu; struct strbuf *strbuf; unsigned long regs, reg_base; @@ -1054,25 +529,28 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) pr = of_get_property(dp, "reg", NULL); if (!pr) { - prom_printf("sbus_iommu_init: Cannot map SYSIO control registers.\n"); + prom_printf("sbus_iommu_init: Cannot map SYSIO " + "control registers.\n"); prom_halt(); } regs = pr->phys_addr; - info = kzalloc(sizeof(*info), GFP_ATOMIC); - if (info == NULL) { - prom_printf("sbus_iommu_init: Fatal error, " - "kmalloc(info) failed\n"); - prom_halt(); - } + iommu = kzalloc(sizeof(*iommu), GFP_ATOMIC); + if (!iommu) + goto fatal_memory_error; + strbuf = kzalloc(sizeof(*strbuf), GFP_ATOMIC); + if (!strbuf) + goto fatal_memory_error; - iommu = &info->iommu; - strbuf = &info->strbuf; + sbus->ofdev.dev.archdata.iommu = iommu; + sbus->ofdev.dev.archdata.stc = strbuf; reg_base = regs + SYSIO_IOMMUREG_BASE; iommu->iommu_control = reg_base + IOMMU_CONTROL; iommu->iommu_tsbbase = reg_base + IOMMU_TSBBASE; iommu->iommu_flush = reg_base + IOMMU_FLUSH; + iommu->iommu_tags = iommu->iommu_control + + (IOMMU_TAGDIAG - IOMMU_CONTROL); reg_base = regs + SYSIO_STRBUFREG_BASE; strbuf->strbuf_control = reg_base + STRBUF_CONTROL; @@ -1093,14 +571,12 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) */ iommu->write_complete_reg = regs + 0x2000UL; - /* Link into SYSIO software state. */ - sbus->iommu = info; - printk("SYSIO: UPA portID %x, at %016lx\n", sbus->portid, regs); /* Setup for TSB_SIZE=7, TBW_SIZE=0, MMU_DE=1, MMU_EN=1 */ - sbus_iommu_table_init(iommu, IO_TSB_SIZE); + if (iommu_table_init(iommu, IO_TSB_SIZE, MAP_BASE, 0xffffffff)) + goto fatal_memory_error; control = upa_readq(iommu->iommu_control); control = ((7UL << 16UL) | @@ -1157,6 +633,10 @@ static void __init sbus_iommu_init(int __node, struct sbus_bus *sbus) starfire_hookup(sbus->portid); sysio_register_error_handlers(sbus); + return; + +fatal_memory_error: + prom_printf("sbus_iommu_init: Fatal memory allocation error.\n"); } void sbus_fill_device_irq(struct sbus_dev *sdev) diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c index 2553629ec15..c37d7c2587f 100644 --- a/drivers/sbus/sbus.c +++ b/drivers/sbus/sbus.c @@ -210,6 +210,10 @@ static void __init walk_children(struct device_node *dp, struct sbus_dev *parent sdev->bus = sbus; sdev->parent = parent; + sdev->ofdev.dev.archdata.iommu = + sbus->ofdev.dev.archdata.iommu; + sdev->ofdev.dev.archdata.stc = + sbus->ofdev.dev.archdata.stc; fill_sbus_device(dp, sdev); @@ -269,6 +273,11 @@ static void __init build_one_sbus(struct device_node *dp, int num_sbus) sdev->bus = sbus; sdev->parent = NULL; + sdev->ofdev.dev.archdata.iommu = + sbus->ofdev.dev.archdata.iommu; + sdev->ofdev.dev.archdata.stc = + sbus->ofdev.dev.archdata.stc; + fill_sbus_device(dev_dp, sdev); walk_children(dev_dp, sdev, sbus); diff --git a/include/asm-sparc/device.h b/include/asm-sparc/device.h index 4a56d84d69c..c0a7786d65f 100644 --- a/include/asm-sparc/device.h +++ b/include/asm-sparc/device.h @@ -10,6 +10,10 @@ struct device_node; struct of_device; struct dev_archdata { + void *iommu; + void *stc; + void *host_controller; + struct device_node *prom_node; struct of_device *op; }; diff --git a/include/asm-sparc64/dma-mapping.h b/include/asm-sparc64/dma-mapping.h index c58ec1661df..0a1006692bb 100644 --- a/include/asm-sparc64/dma-mapping.h +++ b/include/asm-sparc64/dma-mapping.h @@ -1,307 +1,134 @@ #ifndef _ASM_SPARC64_DMA_MAPPING_H #define _ASM_SPARC64_DMA_MAPPING_H - -#ifdef CONFIG_PCI - -/* we implement the API below in terms of the existing PCI one, - * so include it */ -#include -/* need struct page definitions */ +#include #include -#include - -static inline int -dma_supported(struct device *dev, u64 mask) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return pci_dma_supported(to_pci_dev(dev), mask); -} - -static inline int -dma_set_mask(struct device *dev, u64 dma_mask) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return pci_set_dma_mask(to_pci_dev(dev), dma_mask); -} - -static inline void * -dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, - gfp_t flag) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return pci_iommu_ops->alloc_consistent(to_pci_dev(dev), size, dma_handle, flag); -} - -static inline void -dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, - dma_addr_t dma_handle) -{ - BUG_ON(dev->bus != &pci_bus_type); - - pci_free_consistent(to_pci_dev(dev), size, cpu_addr, dma_handle); -} - -static inline dma_addr_t -dma_map_single(struct device *dev, void *cpu_addr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return pci_map_single(to_pci_dev(dev), cpu_addr, size, (int)direction); -} - -static inline void -dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - pci_unmap_single(to_pci_dev(dev), dma_addr, size, (int)direction); -} - -static inline dma_addr_t -dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return pci_map_page(to_pci_dev(dev), page, offset, size, (int)direction); -} - -static inline void -dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - pci_unmap_page(to_pci_dev(dev), dma_address, size, (int)direction); -} - -static inline int -dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); -} - -static inline void -dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - enum dma_data_direction direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - pci_unmap_sg(to_pci_dev(dev), sg, nhwentries, (int)direction); -} - -static inline void -dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, - size, (int)direction); -} - -static inline void -dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, - size, (int)direction); -} - -static inline void -dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, nelems, (int)direction); -} - -static inline void -dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) -{ - BUG_ON(dev->bus != &pci_bus_type); - - pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, nelems, (int)direction); -} - -static inline int -dma_mapping_error(dma_addr_t dma_addr) -{ - return pci_dma_mapping_error(dma_addr); -} - -#else - -struct device; -struct page; -struct scatterlist; - -static inline int -dma_supported(struct device *dev, u64 mask) -{ - BUG(); - return 0; -} - -static inline int -dma_set_mask(struct device *dev, u64 dma_mask) -{ - BUG(); - return 0; -} +#define DMA_ERROR_CODE (~(dma_addr_t)0x0) + +struct dma_ops { + void *(*alloc_coherent)(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag); + void (*free_coherent)(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle); + dma_addr_t (*map_single)(struct device *dev, void *cpu_addr, + size_t size, + enum dma_data_direction direction); + void (*unmap_single)(struct device *dev, dma_addr_t dma_addr, + size_t size, + enum dma_data_direction direction); + int (*map_sg)(struct device *dev, struct scatterlist *sg, int nents, + enum dma_data_direction direction); + void (*unmap_sg)(struct device *dev, struct scatterlist *sg, + int nhwentries, + enum dma_data_direction direction); + void (*sync_single_for_cpu)(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction); + void (*sync_single_for_device)(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction); + void (*sync_sg_for_cpu)(struct device *dev, struct scatterlist *sg, + int nelems, + enum dma_data_direction direction); + void (*sync_sg_for_device)(struct device *dev, struct scatterlist *sg, + int nelems, + enum dma_data_direction direction); +}; +extern const struct dma_ops *dma_ops; + +extern int dma_supported(struct device *dev, u64 mask); +extern int dma_set_mask(struct device *dev, u64 dma_mask); static inline void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) + dma_addr_t *dma_handle, gfp_t flag) { - BUG(); - return NULL; + return dma_ops->alloc_coherent(dev, size, dma_handle, flag); } static inline void dma_free_coherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle) + void *cpu_addr, dma_addr_t dma_handle) { - BUG(); + dma_ops->free_coherent(dev, size, cpu_addr, dma_handle); } -static inline dma_addr_t -dma_map_single(struct device *dev, void *cpu_addr, size_t size, - enum dma_data_direction direction) +static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, + size_t size, + enum dma_data_direction direction) { - BUG(); - return 0; + return dma_ops->map_single(dev, cpu_addr, size, direction); } -static inline void -dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) +static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, + size_t size, + enum dma_data_direction direction) { - BUG(); + dma_ops->unmap_single(dev, dma_addr, size, direction); } -static inline dma_addr_t -dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction) +static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) { - BUG(); - return 0; + return dma_ops->map_single(dev, page_address(page) + offset, + size, direction); } -static inline void -dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, - enum dma_data_direction direction) +static inline void dma_unmap_page(struct device *dev, dma_addr_t dma_address, + size_t size, + enum dma_data_direction direction) { - BUG(); + dma_ops->unmap_single(dev, dma_address, size, direction); } -static inline int -dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, - enum dma_data_direction direction) +static inline int dma_map_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) { - BUG(); - return 0; + return dma_ops->map_sg(dev, sg, nents, direction); } -static inline void -dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries, - enum dma_data_direction direction) +static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sg, + int nents, enum dma_data_direction direction) { - BUG(); + dma_ops->unmap_sg(dev, sg, nents, direction); } -static inline void -dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) +static inline void dma_sync_single_for_cpu(struct device *dev, + dma_addr_t dma_handle, size_t size, + enum dma_data_direction direction) { - BUG(); + dma_ops->sync_single_for_cpu(dev, dma_handle, size, direction); } -static inline void -dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) +static inline void dma_sync_single_for_device(struct device *dev, + dma_addr_t dma_handle, + size_t size, + enum dma_data_direction direction) { - BUG(); + dma_ops->sync_single_for_device(dev, dma_handle, size, direction); } -static inline void -dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) +static inline void dma_sync_sg_for_cpu(struct device *dev, + struct scatterlist *sg, int nelems, + enum dma_data_direction direction) { - BUG(); + dma_ops->sync_sg_for_cpu(dev, sg, nelems, direction); } -static inline void -dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems, - enum dma_data_direction direction) +static inline void dma_sync_sg_for_device(struct device *dev, + struct scatterlist *sg, int nelems, + enum dma_data_direction direction) { - BUG(); + dma_ops->sync_sg_for_device(dev, sg, nelems, direction); } -static inline int -dma_mapping_error(dma_addr_t dma_addr) +static inline int dma_mapping_error(dma_addr_t dma_addr) { - BUG(); - return 0; + return (dma_addr == DMA_ERROR_CODE); } -#endif /* PCI */ - - -/* Now for the API extensions over the pci_ one */ - #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) #define dma_is_consistent(d, h) (1) -static inline int -dma_get_cache_alignment(void) -{ - /* no easy way to get cache size on all processors, so return - * the maximum possible, to be safe */ - return (1 << INTERNODE_CACHE_SHIFT); -} - -static inline void -dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - /* just sync everything, that's all the pci API can do */ - dma_sync_single_for_cpu(dev, dma_handle, offset+size, direction); -} - -static inline void -dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, - unsigned long offset, size_t size, - enum dma_data_direction direction) -{ - /* just sync everything, that's all the pci API can do */ - dma_sync_single_for_device(dev, dma_handle, offset+size, direction); -} - -static inline void -dma_cache_sync(struct device *dev, void *vaddr, size_t size, - enum dma_data_direction direction) -{ - /* could define this in terms of the dma_cache ... operations, - * but if you get this on a platform, you should convert the platform - * to using the generic device DMA API */ - BUG(); -} - #endif /* _ASM_SPARC64_DMA_MAPPING_H */ diff --git a/include/asm-sparc64/iommu.h b/include/asm-sparc64/iommu.h index 0b1813f4104..9eac6676caf 100644 --- a/include/asm-sparc64/iommu.h +++ b/include/asm-sparc64/iommu.h @@ -1,7 +1,6 @@ -/* $Id: iommu.h,v 1.10 2001/03/08 09:55:56 davem Exp $ - * iommu.h: Definitions for the sun5 IOMMU. +/* iommu.h: Definitions for the sun5 IOMMU. * - * Copyright (C) 1996, 1999 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996, 1999, 2007 David S. Miller (davem@davemloft.net) */ #ifndef _SPARC64_IOMMU_H #define _SPARC64_IOMMU_H @@ -33,6 +32,7 @@ struct iommu { unsigned long iommu_tsbbase; unsigned long iommu_flush; unsigned long iommu_flushinv; + unsigned long iommu_tags; unsigned long iommu_ctxflush; unsigned long write_complete_reg; unsigned long dummy_page; @@ -54,4 +54,7 @@ struct strbuf { volatile unsigned long __flushflag_buf[(64+(64-1)) / sizeof(long)]; }; -#endif /* !(_SPARC_IOMMU_H) */ +extern int iommu_table_init(struct iommu *iommu, int tsbsize, + u32 dma_offset, u32 dma_addr_mask); + +#endif /* !(_SPARC64_IOMMU_H) */ diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h index 600afe5ae2e..8116e8f6062 100644 --- a/include/asm-sparc64/parport.h +++ b/include/asm-sparc64/parport.h @@ -117,7 +117,7 @@ static int __devinit ecpp_probe(struct of_device *op, const struct of_device_id if (!strcmp(parent->name, "dma")) { p = parport_pc_probe_port(base, base + 0x400, op->irqs[0], PARPORT_DMA_NOFIFO, - op->dev.parent); + op->dev.parent->parent); if (!p) return -ENOMEM; dev_set_drvdata(&op->dev, p); diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h index e11ac100f04..1393e57d50f 100644 --- a/include/asm-sparc64/pci.h +++ b/include/asm-sparc64/pci.h @@ -3,8 +3,7 @@ #ifdef __KERNEL__ -#include -#include +#include /* Can be used to override the logic in pci_scan_bus for skipping * already-configured bus numbers - to be used for buggy BIOSes @@ -30,80 +29,42 @@ static inline void pcibios_penalize_isa_irq(int irq, int active) /* We don't do dynamic PCI IRQ allocation */ } -/* Dynamic DMA mapping stuff. - */ - /* The PCI address space does not equal the physical memory * address space. The networking and block device layers use * this boolean for bounce buffer decisions. */ #define PCI_DMA_BUS_IS_PHYS (0) -#include - -struct pci_dev; - -struct pci_iommu_ops { - void *(*alloc_consistent)(struct pci_dev *, size_t, dma_addr_t *, gfp_t); - void (*free_consistent)(struct pci_dev *, size_t, void *, dma_addr_t); - dma_addr_t (*map_single)(struct pci_dev *, void *, size_t, int); - void (*unmap_single)(struct pci_dev *, dma_addr_t, size_t, int); - int (*map_sg)(struct pci_dev *, struct scatterlist *, int, int); - void (*unmap_sg)(struct pci_dev *, struct scatterlist *, int, int); - void (*dma_sync_single_for_cpu)(struct pci_dev *, dma_addr_t, size_t, int); - void (*dma_sync_sg_for_cpu)(struct pci_dev *, struct scatterlist *, int, int); -}; - -extern const struct pci_iommu_ops *pci_iommu_ops; - -/* Allocate and map kernel buffer using consistent mode DMA for a device. - * hwdev should be valid struct pci_dev pointer for PCI devices. - */ -static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) +static inline void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, + dma_addr_t *dma_handle) { - return pci_iommu_ops->alloc_consistent(hwdev, size, dma_handle, GFP_ATOMIC); + return dma_alloc_coherent(&pdev->dev, size, dma_handle, GFP_ATOMIC); } -/* Free and unmap a consistent DMA buffer. - * cpu_addr is what was returned from pci_alloc_consistent, - * size must be the same as what as passed into pci_alloc_consistent, - * and likewise dma_addr must be the same as what *dma_addrp was set to. - * - * References to the memory and mappings associated with cpu_addr/dma_addr - * past this call are illegal. - */ -static inline void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) +static inline void pci_free_consistent(struct pci_dev *pdev, size_t size, + void *vaddr, dma_addr_t dma_handle) { - return pci_iommu_ops->free_consistent(hwdev, size, vaddr, dma_handle); + return dma_free_coherent(&pdev->dev, size, vaddr, dma_handle); } -/* Map a single buffer of the indicated size for DMA in streaming mode. - * The 32-bit bus address to use is returned. - * - * Once the device is given the dma address, the device owns this memory - * until either pci_unmap_single or pci_dma_sync_single_for_cpu is performed. - */ -static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) +static inline dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, + size_t size, int direction) { - return pci_iommu_ops->map_single(hwdev, ptr, size, direction); + return dma_map_single(&pdev->dev, ptr, size, + (enum dma_data_direction) direction); } -/* Unmap a single streaming mode DMA translation. The dma_addr and size - * must match what was provided for in a previous pci_map_single call. All - * other usages are undefined. - * - * After this call, reads by the cpu to the buffer are guaranteed to see - * whatever the device wrote there. - */ -static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, size_t size, int direction) +static inline void pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, + size_t size, int direction) { - pci_iommu_ops->unmap_single(hwdev, dma_addr, size, direction); + dma_unmap_single(&pdev->dev, dma_addr, size, + (enum dma_data_direction) direction); } -/* No highmem on sparc64, plus we have an IOMMU, so mapping pages is easy. */ #define pci_map_page(dev, page, off, size, dir) \ pci_map_single(dev, (page_address(page) + (off)), size, dir) -#define pci_unmap_page(dev,addr,sz,dir) pci_unmap_single(dev,addr,sz,dir) +#define pci_unmap_page(dev,addr,sz,dir) \ + pci_unmap_single(dev,addr,sz,dir) /* pci_unmap_{single,page} is not a nop, thus... */ #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME) \ @@ -119,75 +80,48 @@ static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, #define pci_unmap_len_set(PTR, LEN_NAME, VAL) \ (((PTR)->LEN_NAME) = (VAL)) -/* Map a set of buffers described by scatterlist in streaming - * mode for DMA. This is the scatter-gather version of the - * above pci_map_single interface. Here the scatter gather list - * elements are each tagged with the appropriate dma address - * and length. They are obtained via sg_dma_{address,length}(SG). - * - * NOTE: An implementation may be able to use a smaller number of - * DMA address/length pairs than there are SG table elements. - * (for example via virtual mapping capabilities) - * The routine returns the number of addr/length pairs actually - * used, at most nents. - * - * Device ownership issues as mentioned above for pci_map_single are - * the same here. - */ -static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nents, int direction) +static inline int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, + int nents, int direction) { - return pci_iommu_ops->map_sg(hwdev, sg, nents, direction); + return dma_map_sg(&pdev->dev, sg, nents, + (enum dma_data_direction) direction); } -/* Unmap a set of streaming mode DMA translations. - * Again, cpu read rules concerning calls here are the same as for - * pci_unmap_single() above. - */ -static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, int nhwents, int direction) +static inline void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, + int nents, int direction) { - pci_iommu_ops->unmap_sg(hwdev, sg, nhwents, direction); + dma_unmap_sg(&pdev->dev, sg, nents, + (enum dma_data_direction) direction); } -/* Make physical memory consistent for a single - * streaming mode DMA translation after a transfer. - * - * If you perform a pci_map_single() but wish to interrogate the - * buffer using the cpu, yet do not wish to teardown the PCI dma - * mapping, you must call this function before doing so. At the - * next point you give the PCI dma address back to the card, you - * must first perform a pci_dma_sync_for_device, and then the - * device again owns the buffer. - */ -static inline void pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, size_t size, int direction) +static inline void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, + dma_addr_t dma_handle, + size_t size, int direction) { - pci_iommu_ops->dma_sync_single_for_cpu(hwdev, dma_handle, size, direction); + dma_sync_single_for_cpu(&pdev->dev, dma_handle, size, + (enum dma_data_direction) direction); } -static inline void -pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, - size_t size, int direction) +static inline void pci_dma_sync_single_for_device(struct pci_dev *pdev, + dma_addr_t dma_handle, + size_t size, int direction) { /* No flushing needed to sync cpu writes to the device. */ - BUG_ON(direction == PCI_DMA_NONE); } -/* Make physical memory consistent for a set of streaming - * mode DMA translations after a transfer. - * - * The same as pci_dma_sync_single_* but for a scatter-gather list, - * same rules and usage. - */ -static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction) +static inline void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, + struct scatterlist *sg, + int nents, int direction) { - pci_iommu_ops->dma_sync_sg_for_cpu(hwdev, sg, nelems, direction); + dma_sync_sg_for_cpu(&pdev->dev, sg, nents, + (enum dma_data_direction) direction); } -static inline void -pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, - int nelems, int direction) +static inline void pci_dma_sync_sg_for_device(struct pci_dev *pdev, + struct scatterlist *sg, + int nelems, int direction) { /* No flushing needed to sync cpu writes to the device. */ - BUG_ON(direction == PCI_DMA_NONE); } /* Return whether the given PCI device DMA address mask can @@ -206,11 +140,9 @@ extern int pci_dma_supported(struct pci_dev *hwdev, u64 mask); #define PCI64_REQUIRED_MASK (~(dma64_addr_t)0) #define PCI64_ADDR_BASE 0xfffc000000000000UL -#define PCI_DMA_ERROR_CODE (~(dma_addr_t)0x0) - static inline int pci_dma_mapping_error(dma_addr_t dma_addr) { - return (dma_addr == PCI_DMA_ERROR_CODE); + return dma_mapping_error(dma_addr); } #ifdef CONFIG_PCI diff --git a/include/asm-sparc64/sbus.h b/include/asm-sparc64/sbus.h index 7efd49d31bb..0151cad486f 100644 --- a/include/asm-sparc64/sbus.h +++ b/include/asm-sparc64/sbus.h @@ -1,7 +1,6 @@ -/* $Id: sbus.h,v 1.14 2000/02/18 13:50:55 davem Exp $ - * sbus.h: Defines for the Sun SBus. +/* sbus.h: Defines for the Sun SBus. * - * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com) + * Copyright (C) 1996, 1999, 2007 David S. Miller (davem@davemloft.net) */ #ifndef _SPARC64_SBUS_H @@ -69,7 +68,6 @@ struct sbus_dev { /* This struct describes the SBus(s) found on this machine. */ struct sbus_bus { struct of_device ofdev; - void *iommu; /* Opaque IOMMU cookie */ struct sbus_dev *devices; /* Tree of SBUS devices */ struct sbus_bus *next; /* Next SBUS in system */ int prom_node; /* OBP node of SBUS */ @@ -102,9 +100,18 @@ extern struct sbus_bus *sbus_root; extern void sbus_set_sbus64(struct sbus_dev *, int); extern void sbus_fill_device_irq(struct sbus_dev *); -/* These yield IOMMU mappings in consistent mode. */ -extern void *sbus_alloc_consistent(struct sbus_dev *, size_t, dma_addr_t *dma_addrp); -extern void sbus_free_consistent(struct sbus_dev *, size_t, void *, dma_addr_t); +static inline void *sbus_alloc_consistent(struct sbus_dev *sdev , size_t size, + dma_addr_t *dma_handle) +{ + return dma_alloc_coherent(&sdev->ofdev.dev, size, + dma_handle, GFP_ATOMIC); +} + +static inline void sbus_free_consistent(struct sbus_dev *sdev, size_t size, + void *vaddr, dma_addr_t dma_handle) +{ + return dma_free_coherent(&sdev->ofdev.dev, size, vaddr, dma_handle); +} #define SBUS_DMA_BIDIRECTIONAL DMA_BIDIRECTIONAL #define SBUS_DMA_TODEVICE DMA_TO_DEVICE @@ -112,18 +119,67 @@ extern void sbus_free_consistent(struct sbus_dev *, size_t, void *, dma_addr_t); #define SBUS_DMA_NONE DMA_NONE /* All the rest use streaming mode mappings. */ -extern dma_addr_t sbus_map_single(struct sbus_dev *, void *, size_t, int); -extern void sbus_unmap_single(struct sbus_dev *, dma_addr_t, size_t, int); -extern int sbus_map_sg(struct sbus_dev *, struct scatterlist *, int, int); -extern void sbus_unmap_sg(struct sbus_dev *, struct scatterlist *, int, int); +static inline dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *ptr, + size_t size, int direction) +{ + return dma_map_single(&sdev->ofdev.dev, ptr, size, + (enum dma_data_direction) direction); +} + +static inline void sbus_unmap_single(struct sbus_dev *sdev, + dma_addr_t dma_addr, size_t size, + int direction) +{ + dma_unmap_single(&sdev->ofdev.dev, dma_addr, size, + (enum dma_data_direction) direction); +} + +static inline int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, + int nents, int direction) +{ + return dma_map_sg(&sdev->ofdev.dev, sg, nents, + (enum dma_data_direction) direction); +} + +static inline void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, + int nents, int direction) +{ + dma_unmap_sg(&sdev->ofdev.dev, sg, nents, + (enum dma_data_direction) direction); +} /* Finally, allow explicit synchronization of streamable mappings. */ -extern void sbus_dma_sync_single_for_cpu(struct sbus_dev *, dma_addr_t, size_t, int); +static inline void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, + dma_addr_t dma_handle, + size_t size, int direction) +{ + dma_sync_single_for_cpu(&sdev->ofdev.dev, dma_handle, size, + (enum dma_data_direction) direction); +} #define sbus_dma_sync_single sbus_dma_sync_single_for_cpu -extern void sbus_dma_sync_single_for_device(struct sbus_dev *, dma_addr_t, size_t, int); -extern void sbus_dma_sync_sg_for_cpu(struct sbus_dev *, struct scatterlist *, int, int); + +static inline void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, + dma_addr_t dma_handle, + size_t size, int direction) +{ + /* No flushing needed to sync cpu writes to the device. */ +} + +static inline void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, + struct scatterlist *sg, + int nents, int direction) +{ + dma_sync_sg_for_cpu(&sdev->ofdev.dev, sg, nents, + (enum dma_data_direction) direction); +} #define sbus_dma_sync_sg sbus_dma_sync_sg_for_cpu -extern void sbus_dma_sync_sg_for_device(struct sbus_dev *, struct scatterlist *, int, int); + +static inline void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, + struct scatterlist *sg, + int nents, int direction) +{ + /* No flushing needed to sync cpu writes to the device. */ +} extern void sbus_arch_bus_ranges_init(struct device_node *, struct sbus_bus *); extern void sbus_setup_iommu(struct sbus_bus *, struct device_node *); -- cgit v1.2.3 From 9b539c03b2cb16879ce2e808ce5c687da1dba27c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sat, 28 Jul 2007 23:39:30 -0700 Subject: [SPARC64]: asm-sparc64/floppy.h needs linux/pci.h It uses pci_dev, calls pci_map_*(), etc. Signed-off-by: David S. Miller --- include/asm-sparc64/floppy.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h index 4aa0925e1b1..1783239c7b4 100644 --- a/include/asm-sparc64/floppy.h +++ b/include/asm-sparc64/floppy.h @@ -1,7 +1,6 @@ -/* $Id: floppy.h,v 1.32 2001/10/26 17:59:36 davem Exp $ - * asm-sparc64/floppy.h: Sparc specific parts of the Floppy driver. +/* floppy.h: Sparc specific parts of the Floppy driver. * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1996, 2007 David S. Miller (davem@davemloft.net) * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * * Ultra/PCI support added: Sep 1997 Eddie C. Dost (ecd@skynet.be) @@ -11,6 +10,7 @@ #define __ASM_SPARC64_FLOPPY_H #include +#include #include #include -- cgit v1.2.3 From 8163904e660a30be800a3361df69bf9dad3b44cd Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 29 Jul 2007 00:50:42 -0700 Subject: [SPARC]: Mark SBUS framebuffer ioctls as IGNORE in compat_ioctl.c They are handled in a ->compat_ioctl() handler, so it's just noise when compat_ioctl.c warns which occurs when they are used on non-SBUS framebuffer devices. Signed-off-by: David S. Miller --- drivers/video/sbuslib.c | 25 ------------------------- fs/compat_ioctl.c | 20 ++++++++++++++++++++ include/asm-sparc64/fbio.h | 28 ++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/drivers/video/sbuslib.c b/drivers/video/sbuslib.c index 34ef859ee41..963a454b707 100644 --- a/drivers/video/sbuslib.c +++ b/drivers/video/sbuslib.c @@ -190,17 +190,6 @@ int sbusfb_ioctl_helper(unsigned long cmd, unsigned long arg, EXPORT_SYMBOL(sbusfb_ioctl_helper); #ifdef CONFIG_COMPAT -struct fbcmap32 { - int index; /* first element (0 origin) */ - int count; - u32 red; - u32 green; - u32 blue; -}; - -#define FBIOPUTCMAP32 _IOW('F', 3, struct fbcmap32) -#define FBIOGETCMAP32 _IOW('F', 4, struct fbcmap32) - static int fbiogetputcmap(struct fb_info *info, unsigned int cmd, unsigned long arg) { struct fbcmap32 __user *argp = (void __user *)arg; @@ -223,20 +212,6 @@ static int fbiogetputcmap(struct fb_info *info, unsigned int cmd, unsigned long (unsigned long)p); } -struct fbcursor32 { - short set; /* what to set, choose from the list above */ - short enable; /* cursor on/off */ - struct fbcurpos pos; /* cursor position */ - struct fbcurpos hot; /* cursor hot spot */ - struct fbcmap32 cmap; /* color map info */ - struct fbcurpos size; /* cursor bit map size */ - u32 image; /* cursor image bits */ - u32 mask; /* cursor mask bits */ -}; - -#define FBIOSCURSOR32 _IOW('F', 24, struct fbcursor32) -#define FBIOGCURSOR32 _IOW('F', 25, struct fbcursor32) - static int fbiogscursor(struct fb_info *info, unsigned long arg) { struct fbcursor __user *p = compat_alloc_user_space(sizeof(*p)); diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index e440a7b95d0..2bc1428d621 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c @@ -115,6 +115,10 @@ #include #include +#ifdef CONFIG_SPARC +#include +#endif + static int do_ioctl32_pointer(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *f) { @@ -3493,6 +3497,22 @@ IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32) /* loop */ IGNORE_IOCTL(LOOP_CLR_FD) + +#ifdef CONFIG_SPARC +/* Sparc framebuffers, handled in sbusfb_compat_ioctl() */ +IGNORE_IOCTL(FBIOGTYPE) +IGNORE_IOCTL(FBIOSATTR) +IGNORE_IOCTL(FBIOGATTR) +IGNORE_IOCTL(FBIOSVIDEO) +IGNORE_IOCTL(FBIOGVIDEO) +IGNORE_IOCTL(FBIOSCURPOS) +IGNORE_IOCTL(FBIOGCURPOS) +IGNORE_IOCTL(FBIOGCURMAX) +IGNORE_IOCTL(FBIOPUTCMAP32) +IGNORE_IOCTL(FBIOGETCMAP32) +IGNORE_IOCTL(FBIOSCURSOR32) +IGNORE_IOCTL(FBIOGCURSOR32) +#endif }; #define IOCTL_HASHSIZE 256 diff --git a/include/asm-sparc64/fbio.h b/include/asm-sparc64/fbio.h index 500026d9f6e..b9215a0907d 100644 --- a/include/asm-sparc64/fbio.h +++ b/include/asm-sparc64/fbio.h @@ -2,6 +2,7 @@ #define __LINUX_FBIO_H #include +#include /* Constants used for fbio SunOS compatibility */ /* (C) 1996 Miguel de Icaza */ @@ -299,4 +300,31 @@ struct fb_clut32 { #define LEO_LD_GBL_MAP 0x01009000 #define LEO_UNK2_MAP 0x0100a000 +#ifdef __KERNEL__ +struct fbcmap32 { + int index; /* first element (0 origin) */ + int count; + u32 red; + u32 green; + u32 blue; +}; + +#define FBIOPUTCMAP32 _IOW('F', 3, struct fbcmap32) +#define FBIOGETCMAP32 _IOW('F', 4, struct fbcmap32) + +struct fbcursor32 { + short set; /* what to set, choose from the list above */ + short enable; /* cursor on/off */ + struct fbcurpos pos; /* cursor position */ + struct fbcurpos hot; /* cursor hot spot */ + struct fbcmap32 cmap; /* color map info */ + struct fbcurpos size; /* cursor bit map size */ + u32 image; /* cursor image bits */ + u32 mask; /* cursor mask bits */ +}; + +#define FBIOSCURSOR32 _IOW('F', 24, struct fbcursor32) +#define FBIOGCURSOR32 _IOW('F', 25, struct fbcursor32) +#endif + #endif /* __LINUX_FBIO_H */ -- cgit v1.2.3 From f623f388e4f83c01ac23f228247a6a4b9cc71111 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 29 Jul 2007 02:10:37 -0700 Subject: [SPARC]: Fix serial console node string creation. The string setting code depends upon the original value of the "skip" variable, not the one that gets modified by the node traversal loop. Based upon a patch by Mark Fortescue. Signed-off-by: David S. Miller --- arch/sparc/kernel/prom.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index e3a537650db..39fbd3c8ab0 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c @@ -415,7 +415,7 @@ static void __init of_console_init(void) unsigned long flags; const char *type; phandle node; - int skip, fd; + int skip, tmp, fd; of_console_path = prom_early_alloc(256); @@ -442,8 +442,9 @@ static void __init of_console_init(void) prom_halt(); } + tmp = skip; for_each_node_by_type(dp, type) { - if (!skip--) + if (!tmp--) break; } if (!dp) { -- cgit v1.2.3 From c1f193a7aed1b468617bb26075777c0c2f4f597a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 30 Jul 2007 00:17:12 -0700 Subject: [SPARC64]: Fix show_stack() when stack argument is NULL. It didn't handle that case at all, and now dump_stack() can be implemented directly as show_stack(current, NULL) Signed-off-by: David S. Miller --- arch/sparc64/kernel/traps.c | 18 +++++++++++------- arch/sparc64/mm/fault.c | 5 +---- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index 6ef2d299fb1..6ef42b8e53d 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -2134,12 +2134,20 @@ static void user_instruction_dump (unsigned int __user *pc) void show_stack(struct task_struct *tsk, unsigned long *_ksp) { unsigned long pc, fp, thread_base, ksp; - void *tp = task_stack_page(tsk); + struct thread_info *tp; struct reg_window *rw; int count = 0; ksp = (unsigned long) _ksp; - + if (!tsk) + tsk = current; + tp = task_thread_info(tsk); + if (ksp == 0UL) { + if (tsk == current) + asm("mov %%fp, %0" : "=r" (ksp)); + else + ksp = tp->ksp; + } if (tp == current_thread_info()) flushw_all(); @@ -2168,11 +2176,7 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp) void dump_stack(void) { - unsigned long *ksp; - - __asm__ __volatile__("mov %%fp, %0" - : "=r" (ksp)); - show_stack(current, ksp); + show_stack(current, NULL); } EXPORT_SYMBOL(dump_stack); diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c index 17123e9ecf7..9f7740eee8d 100644 --- a/arch/sparc64/mm/fault.c +++ b/arch/sparc64/mm/fault.c @@ -112,15 +112,12 @@ static void __kprobes unhandled_fault(unsigned long address, static void bad_kernel_pc(struct pt_regs *regs, unsigned long vaddr) { - unsigned long *ksp; - printk(KERN_CRIT "OOPS: Bogus kernel PC [%016lx] in fault handler\n", regs->tpc); printk(KERN_CRIT "OOPS: RPC [%016lx]\n", regs->u_regs[15]); print_symbol("RPC: <%s>\n", regs->u_regs[15]); printk(KERN_CRIT "OOPS: Fault was to vaddr[%lx]\n", vaddr); - __asm__("mov %%sp, %0" : "=r" (ksp)); - show_stack(current, ksp); + dump_stack(); unhandled_fault(regs->tpc, current, regs); } -- cgit v1.2.3