summaryrefslogtreecommitdiff
path: root/drivers/parisc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/parisc')
-rw-r--r--drivers/parisc/Kconfig36
-rw-r--r--drivers/parisc/Makefile20
-rw-r--r--drivers/parisc/asp.c19
-rw-r--r--drivers/parisc/ccio-dma.c425
-rw-r--r--drivers/parisc/ccio-rm-dma.c202
-rw-r--r--drivers/parisc/dino.c120
-rw-r--r--drivers/parisc/eisa.c148
-rw-r--r--drivers/parisc/eisa_eeprom.c22
-rw-r--r--drivers/parisc/eisa_enumerator.c33
-rw-r--r--drivers/parisc/gsc.c54
-rw-r--r--drivers/parisc/gsc.h4
-rw-r--r--drivers/parisc/hppb.c31
-rw-r--r--drivers/parisc/iommu-helpers.h54
-rw-r--r--drivers/parisc/iommu.h55
-rw-r--r--drivers/parisc/iosapic.c84
-rw-r--r--drivers/parisc/iosapic_private.h20
-rw-r--r--drivers/parisc/lasi.c52
-rw-r--r--drivers/parisc/lba_pci.c181
-rw-r--r--drivers/parisc/led.c906
-rw-r--r--drivers/parisc/pdc_stable.c122
-rw-r--r--drivers/parisc/power.c110
-rw-r--r--drivers/parisc/sba_iommu.c384
-rw-r--r--drivers/parisc/superio.c15
-rw-r--r--drivers/parisc/wax.c27
24 files changed, 1429 insertions, 1695 deletions
diff --git a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig
index 592de566e72f..9cbcf15527b6 100644
--- a/drivers/parisc/Kconfig
+++ b/drivers/parisc/Kconfig
@@ -1,7 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-only
menu "Bus options (PCI, PCMCIA, EISA, GSC, ISA)"
config GSC
bool "VSC/GSC/HSC bus support"
+ select HAVE_EISA
+ select HAS_IOPORT
default y
help
The VSC, GSC and HSC busses were used from the earliest 700-series
@@ -46,16 +49,6 @@ config GSC_WAX
used), a HIL interface chip and is also known to be used as the
GSC bridge for an X.25 GSC card.
-config EISA
- bool "EISA support"
- depends on GSC
- help
- Say Y here if you have an EISA bus in your machine. This code
- supports both the Mongoose & Wax EISA adapters. It is sadly
- incomplete and lacks support for card-to-host DMA.
-
-source "drivers/eisa/Kconfig"
-
config ISA
bool "ISA support"
depends on EISA
@@ -63,17 +56,6 @@ config ISA
If you want to plug an ISA card into your EISA bus, say Y here.
Most people should say N.
-config PCI
- bool "PCI support"
- help
- All recent HP machines have PCI slots, and you should say Y here
- if you have a recent machine. If you are convinced you do not have
- PCI slots in your machine (eg a 712), then you may say "N" here.
- Beware that some GSC cards have a Dino onboard and PCI inside them,
- so it may be safest to say "Y" anyway.
-
-source "drivers/pci/Kconfig"
-
config GSC_DINO
bool "GSCtoPCI/Dino PCI support"
depends on PCI && GSC
@@ -103,15 +85,6 @@ config IOMMU_SBA
depends on PCI_LBA
default PCI_LBA
-config IOMMU_HELPER
- bool
- depends on IOMMU_SBA || IOMMU_CCIO
- default y
-
-source "drivers/pcmcia/Kconfig"
-
-source "drivers/pci/hotplug/Kconfig"
-
endmenu
menu "PA-RISC specific drivers"
@@ -127,8 +100,9 @@ config SUPERIO
config CHASSIS_LCD_LED
bool "Chassis LCD and LED support"
+ depends on LEDS_CLASS=y
default y
- select VM_EVENT_COUNTERS
+ select LEDS_TRIGGERS
help
Say Y here if you want to enable support for the Heartbeat,
Disk/Network activities LEDs on some PA-RISC machines,
diff --git a/drivers/parisc/Makefile b/drivers/parisc/Makefile
index f95cab57133a..69860a60bb7a 100644
--- a/drivers/parisc/Makefile
+++ b/drivers/parisc/Makefile
@@ -1,27 +1,27 @@
+# SPDX-License-Identifier: GPL-2.0
#
-# Makefile for most of the non-PCI devices in PA-RISC machines
+# Makefile PCI and non-PCI devices in PA-RISC machines
+#
+# Keep the order below, e.g.
+# - ccio before any potential subdevices
+# - gsc is required before lasi and wax
+# - asp and wax before the EISA adapters for the IRQ regions
+# - EISA must come before PCI to be sure it gets IRQ region
#
-# I/O SAPIC is also on IA64 platforms.
-# The two could be merged into a common source some day.
obj-$(CONFIG_IOSAPIC) += iosapic.o
obj-$(CONFIG_IOMMU_SBA) += sba_iommu.o
obj-$(CONFIG_PCI_LBA) += lba_pci.o
-
-# Only use one of them: ccio-rm-dma is for PCX-W systems *only*
-# obj-$(CONFIG_IOMMU_CCIO) += ccio-rm-dma.o
obj-$(CONFIG_IOMMU_CCIO) += ccio-dma.o
obj-$(CONFIG_GSC) += gsc.o
-
-obj-$(CONFIG_HPPB) += hppb.o
-obj-$(CONFIG_GSC_DINO) += dino.o
obj-$(CONFIG_GSC_LASI) += lasi.o asp.o
obj-$(CONFIG_GSC_WAX) += wax.o
obj-$(CONFIG_EISA) += eisa.o eisa_enumerator.o eisa_eeprom.o
+obj-$(CONFIG_HPPB) += hppb.o
+obj-$(CONFIG_GSC_DINO) += dino.o
obj-$(CONFIG_SUPERIO) += superio.o
obj-$(CONFIG_CHASSIS_LCD_LED) += led.o
obj-$(CONFIG_PDC_STABLE) += pdc_stable.o
obj-y += power.o
-
diff --git a/drivers/parisc/asp.c b/drivers/parisc/asp.c
index 6a1ab2512a53..32af8f095781 100644
--- a/drivers/parisc/asp.c
+++ b/drivers/parisc/asp.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* ASP Device Driver
*
* (c) Copyright 2000 The Puffin Group Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * by Helge Deller <deller@gmx.de>
+ * (c) 2000-2023 by Helge Deller <deller@gmx.de>
*/
#include <linux/errno.h>
@@ -118,13 +114,20 @@ static int __init asp_init_chip(struct parisc_device *dev)
return ret;
}
-static struct parisc_device_id asp_tbl[] = {
+static const struct parisc_device_id asp_tbl[] __initconst = {
{ HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00070 },
{ 0, }
};
+MODULE_DEVICE_TABLE(parisc, asp_tbl);
-struct parisc_driver asp_driver = {
+static struct parisc_driver asp_driver __refdata = {
.name = "asp",
.id_table = asp_tbl,
.probe = asp_init_chip,
};
+
+static int __init asp_init(void)
+{
+ return register_parisc_driver(&asp_driver);
+}
+arch_initcall(asp_init);
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 8b490d77054f..4e7071714356 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
** ccio-dma.c:
** DMA management routines for first generation cache-coherent machines.
@@ -7,22 +8,10 @@
** (c) Copyright 2000 Ryan Bradetich
** (c) Copyright 2000 Hewlett-Packard Company
**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
-**
-**
** "Real Mode" operation refers to U2/Uturn chip operation.
** U2/Uturn were designed to perform coherency checks w/o using
** the I/O MMU - basically what x86 does.
**
-** Philipp Rumpf has a "Real Mode" driver for PCX-W machines at:
-** CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc
-** cvs -z3 co linux/arch/parisc/kernel/dma-rm.c
-**
-** I've rewritten his code to work under TPG's tree. See ccio-rm-dma.c.
-**
** Drawbacks of using Real Mode are:
** o outbound DMA is slower - U2 won't prefetch data (GSC+ XQL signal).
** o Inbound DMA less efficient - U2 can't use DMA_FAST attribute.
@@ -42,19 +31,22 @@
#include <linux/reboot.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/dma-map-ops.h>
#include <linux/scatterlist.h>
#include <linux/iommu-helper.h>
#include <linux/export.h>
#include <asm/byteorder.h>
#include <asm/cache.h> /* for L1_CACHE_BYTES */
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/page.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/hardware.h> /* for register_module() */
#include <asm/parisc-device.h>
+#include "iommu.h"
+
/*
** Choose "ccio" since that's what HP-UX calls it.
** Make it easier for folks to migrate from one to the other :^)
@@ -71,8 +63,6 @@
#undef CCIO_COLLECT_STATS
#endif
-#include <asm/runway.h> /* for proc_runway_root */
-
#ifdef DEBUG_CCIO_INIT
#define DBG_INIT(x...) printk(x)
#else
@@ -97,7 +87,6 @@
#define DBG_RUN_SG(x...)
#endif
-#define CCIO_INLINE inline
#define WRITE_U32(value, addr) __raw_writel(value, addr)
#define READ_U32(addr) __raw_readl(addr)
@@ -111,29 +100,29 @@
#define CMD_TLB_PURGE 33 /* IO_COMMAND to Purge I/O TLB entry */
struct ioa_registers {
- /* Runway Supervisory Set */
- int32_t unused1[12];
- uint32_t io_command; /* Offset 12 */
- uint32_t io_status; /* Offset 13 */
- uint32_t io_control; /* Offset 14 */
- int32_t unused2[1];
-
- /* Runway Auxiliary Register Set */
- uint32_t io_err_resp; /* Offset 0 */
- uint32_t io_err_info; /* Offset 1 */
- uint32_t io_err_req; /* Offset 2 */
- uint32_t io_err_resp_hi; /* Offset 3 */
- uint32_t io_tlb_entry_m; /* Offset 4 */
- uint32_t io_tlb_entry_l; /* Offset 5 */
- uint32_t unused3[1];
- uint32_t io_pdir_base; /* Offset 7 */
- uint32_t io_io_low_hv; /* Offset 8 */
- uint32_t io_io_high_hv; /* Offset 9 */
- uint32_t unused4[1];
- uint32_t io_chain_id_mask; /* Offset 11 */
- uint32_t unused5[2];
- uint32_t io_io_low; /* Offset 14 */
- uint32_t io_io_high; /* Offset 15 */
+ /* Runway Supervisory Set */
+ int32_t unused1[12];
+ uint32_t io_command; /* Offset 12 */
+ uint32_t io_status; /* Offset 13 */
+ uint32_t io_control; /* Offset 14 */
+ int32_t unused2[1];
+
+ /* Runway Auxiliary Register Set */
+ uint32_t io_err_resp; /* Offset 0 */
+ uint32_t io_err_info; /* Offset 1 */
+ uint32_t io_err_req; /* Offset 2 */
+ uint32_t io_err_resp_hi; /* Offset 3 */
+ uint32_t io_tlb_entry_m; /* Offset 4 */
+ uint32_t io_tlb_entry_l; /* Offset 5 */
+ uint32_t unused3[1];
+ uint32_t io_pdir_base; /* Offset 7 */
+ uint32_t io_io_low_hv; /* Offset 8 */
+ uint32_t io_io_high_hv; /* Offset 9 */
+ uint32_t unused4[1];
+ uint32_t io_chain_id_mask; /* Offset 11 */
+ uint32_t unused5[2];
+ uint32_t io_io_low; /* Offset 14 */
+ uint32_t io_io_high; /* Offset 15 */
};
/*
@@ -198,7 +187,7 @@ struct ioa_registers {
** In order for a Runway address to reside within GSC+ extended address space:
** Runway Address [0:7] must identically compare to 8'b11111111
** Runway Address [8:11] must be equal to IO_IO_LOW(_HV)[16:19]
-** Runway Address [12:23] must be greater than or equal to
+** Runway Address [12:23] must be greater than or equal to
** IO_IO_LOW(_HV)[20:31] and less than IO_IO_HIGH(_HV)[20:31].
** Runway Address [24:39] is not used in the comparison.
**
@@ -225,11 +214,11 @@ struct ioa_registers {
struct ioc {
struct ioa_registers __iomem *ioc_regs; /* I/O MMU base address */
u8 *res_map; /* resource map, bit == pdir entry */
- u64 *pdir_base; /* physical base address */
- u32 pdir_size; /* bytes, function of IOV Space size */
- u32 res_hint; /* next available IOVP -
+ __le64 *pdir_base; /* physical base address */
+ u32 pdir_size; /* bytes, function of IOV Space size */
+ u32 res_hint; /* next available IOVP -
circular search */
- u32 res_size; /* size of resource map in bytes */
+ u32 res_size; /* size of resource map in bytes */
spinlock_t res_lock;
#ifdef CCIO_COLLECT_STATS
@@ -249,7 +238,7 @@ struct ioc {
unsigned short cujo20_bug;
/* STUFF We don't need in performance path */
- u32 chainid_shift; /* specify bit location of chain_id */
+ u32 chainid_shift; /* specify bit location of chain_id */
struct ioc *next; /* Linked list of discovered iocs */
const char *name; /* device name from firmware */
unsigned int hw_path; /* the hardware path this ioc is associatd with */
@@ -268,7 +257,7 @@ static int ioc_count;
* Each bit can represent a number of pages.
* LSbs represent lower addresses (IOVA's).
*
-* This was was copied from sba_iommu.c. Don't try to unify
+* This was copied from sba_iommu.c. Don't try to unify
* the two resource managers unless a way to have different
* allocation policies is also adjusted. We'd like to avoid
* I/O TLB thrashing by having resource allocation policy
@@ -293,7 +282,7 @@ static int ioc_count;
** cause the kernel to panic anyhow.
*/
#define CCIO_SEARCH_LOOP(ioc, res_idx, mask, size) \
- for(; res_ptr < res_end; ++res_ptr) { \
+ for (; res_ptr < res_end; ++res_ptr) { \
int ret;\
unsigned int idx;\
idx = (unsigned int)((unsigned long)res_ptr - (unsigned long)ioc->res_map); \
@@ -309,9 +298,9 @@ static int ioc_count;
#define CCIO_FIND_FREE_MAPPING(ioa, res_idx, mask, size) \
u##size *res_ptr = (u##size *)&((ioc)->res_map[ioa->res_hint & ~((size >> 3) - 1)]); \
u##size *res_end = (u##size *)&(ioc)->res_map[ioa->res_size]; \
- CCIO_SEARCH_LOOP(ioc, res_idx, mask, size); \
- res_ptr = (u##size *)&(ioc)->res_map[0]; \
- CCIO_SEARCH_LOOP(ioa, res_idx, mask, size);
+ CCIO_SEARCH_LOOP(ioc, res_idx, mask, size); \
+ res_ptr = (u##size *)&(ioc)->res_map[0]; \
+ CCIO_SEARCH_LOOP(ioa, res_idx, mask, size);
/*
** Find available bit in this ioa's resource map.
@@ -330,7 +319,8 @@ static int ioc_count;
/**
* ccio_alloc_range - Allocate pages in the ioc's resource map.
* @ioc: The I/O Controller.
- * @pages_needed: The requested number of pages to be mapped into the
+ * @dev: The PCI device.
+ * @size: The requested number of bytes to be mapped into the
* I/O Pdir...
*
* This function searches the resource map of the ioc to locate a range
@@ -348,17 +338,16 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size)
BUG_ON(pages_needed == 0);
BUG_ON((pages_needed * IOVP_SIZE) > DMA_CHUNK_SIZE);
-
- DBG_RES("%s() size: %d pages_needed %d\n",
- __func__, size, pages_needed);
+
+ DBG_RES("%s() size: %zu pages_needed %d\n",
+ __func__, size, pages_needed);
/*
** "seek and ye shall find"...praying never hurts either...
** ggg sacrifices another 710 to the computer gods.
*/
- boundary_size = ALIGN((unsigned long long)dma_get_seg_boundary(dev) + 1,
- 1ULL << IOVP_SHIFT) >> IOVP_SHIFT;
+ boundary_size = dma_get_seg_boundary_nr_pages(dev, IOVP_SHIFT);
if (pages_needed <= 8) {
/*
@@ -417,7 +406,7 @@ resource_found:
#define CCIO_FREE_MAPPINGS(ioc, res_idx, mask, size) \
u##size *res_ptr = (u##size *)&((ioc)->res_map[res_idx]); \
BUG_ON((*res_ptr & mask) != mask); \
- *res_ptr &= ~(mask);
+ *res_ptr &= ~(mask);
/**
* ccio_free_range - Free pages from the ioc's resource map.
@@ -438,7 +427,7 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped)
BUG_ON((pages_mapped * IOVP_SIZE) > DMA_CHUNK_SIZE);
BUG_ON(pages_mapped > BITS_PER_LONG);
- DBG_RES("%s(): res_idx: %d pages_mapped %d\n",
+ DBG_RES("%s(): res_idx: %d pages_mapped %lu\n",
__func__, res_idx, pages_mapped);
#ifdef CCIO_COLLECT_STATS
@@ -519,19 +508,19 @@ typedef unsigned long space_t;
** when it passes in BIDIRECTIONAL flag.
*/
static u32 hint_lookup[] = {
- [PCI_DMA_BIDIRECTIONAL] = HINT_STOP_MOST | HINT_SAFE_DMA | IOPDIR_VALID,
- [PCI_DMA_TODEVICE] = HINT_STOP_MOST | HINT_PREFETCH | IOPDIR_VALID,
- [PCI_DMA_FROMDEVICE] = HINT_STOP_MOST | IOPDIR_VALID,
+ [DMA_BIDIRECTIONAL] = HINT_STOP_MOST | HINT_SAFE_DMA | IOPDIR_VALID,
+ [DMA_TO_DEVICE] = HINT_STOP_MOST | HINT_PREFETCH | IOPDIR_VALID,
+ [DMA_FROM_DEVICE] = HINT_STOP_MOST | IOPDIR_VALID,
};
/**
* ccio_io_pdir_entry - Initialize an I/O Pdir.
* @pdir_ptr: A pointer into I/O Pdir.
* @sid: The Space Identifier.
- * @vba: The virtual address.
+ * @pba: The physical address.
* @hints: The DMA Hint.
*
- * Given a virtual address (vba, arg2) and space id, (sid, arg1),
+ * Given a physical address (pba, arg2) and space id, (sid, arg1),
* load the I/O PDIR entry pointed to by pdir_ptr (arg0). Each IO Pdir
* entry consists of 8 bytes as shown below (MSB == bit 0):
*
@@ -553,8 +542,8 @@ static u32 hint_lookup[] = {
* (Load Coherence Index) instruction. The 8 bits used for the virtual
* index are bits 12:19 of the value returned by LCI.
*/
-static void CCIO_INLINE
-ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
+static void
+ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, phys_addr_t pba,
unsigned long hints)
{
register unsigned long pa;
@@ -563,14 +552,12 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
/* We currently only support kernel addresses */
BUG_ON(sid != KERNEL_SPACE);
- mtsp(sid,1);
-
/*
** WORD 1 - low order word
** "hints" parm includes the VALID bit!
** "dep" clobbers the physical address offset bits as well.
*/
- pa = virt_to_phys(vba);
+ pa = pba;
asm volatile("depw %1,31,12,%0" : "+r" (pa) : "r" (hints));
((u32 *)pdir_ptr)[1] = (u32) pa;
@@ -595,7 +582,7 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
** Grab virtual index [0:11]
** Deposit virt_idx bits into I/O PDIR word
*/
- asm volatile ("lci %%r0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
+ asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (phys_to_virt(pba)));
asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci));
asm volatile ("depw %1,15,12,%0" : "+r" (pa) : "r" (ci));
@@ -607,14 +594,13 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
** PCX-T'? Don't know. (eg C110 or similar K-class)
**
** See PDC_MODEL/option 0/SW_CAP word for "Non-coherent IO-PDIR bit".
- ** Hopefully we can patch (NOP) these out at boot time somehow.
**
** "Since PCX-U employs an offset hash that is incompatible with
** the real mode coherence index generation of U2, the PDIR entry
** must be flushed to memory to retain coherence."
*/
- asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
- asm volatile("sync");
+ asm_io_fdc(pdir_ptr);
+ asm_io_sync();
}
/**
@@ -627,7 +613,7 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
*
* FIXME: Can we change the byte_cnt to pages_mapped?
*/
-static CCIO_INLINE void
+static void
ccio_clear_io_tlb(struct ioc *ioc, dma_addr_t iovp, size_t byte_cnt)
{
u32 chain_size = 1 << ioc->chainid_shift;
@@ -660,7 +646,7 @@ ccio_clear_io_tlb(struct ioc *ioc, dma_addr_t iovp, size_t byte_cnt)
*
* FIXME: Can we change byte_cnt to pages_mapped?
*/
-static CCIO_INLINE void
+static void
ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
{
u32 iovp = (u32)CCIO_IOVP(iova);
@@ -680,17 +666,14 @@ ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
** FIXME: PCX_W platforms don't need FDC/SYNC. (eg C360)
** PCX-U/U+ do. (eg C200/C240)
** See PDC_MODEL/option 0/SW_CAP for "Non-coherent IO-PDIR bit".
- **
- ** Hopefully someone figures out how to patch (NOP) the
- ** FDC/SYNC out at boot time.
*/
- asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr[7]));
+ asm_io_fdc(pdir_ptr);
iovp += IOVP_SIZE;
byte_cnt -= IOVP_SIZE;
}
- asm volatile("sync");
+ asm_io_sync();
ccio_clear_io_tlb(ioc, CCIO_IOVP(iova), saved_byte_cnt);
}
@@ -704,8 +687,6 @@ ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
* ccio_dma_supported - Verify the IOMMU supports the DMA address range.
* @dev: The PCI device.
* @mask: A bit mask describing the DMA address range of the device.
- *
- * This function implements the pci_dma_supported function.
*/
static int
ccio_dma_supported(struct device *dev, u64 mask)
@@ -716,21 +697,21 @@ ccio_dma_supported(struct device *dev, u64 mask)
return 0;
}
- /* only support 32-bit devices (ie PCI/GSC) */
- return (int)(mask == 0xffffffffUL);
+ /* only support 32-bit or better devices (ie PCI/GSC) */
+ return (int)(mask >= 0xffffffffUL);
}
/**
* ccio_map_single - Map an address range into the IOMMU.
* @dev: The PCI device.
- * @addr: The start address of the DMA region.
+ * @addr: The physical address of the DMA region.
* @size: The length of the DMA region.
* @direction: The direction of the DMA transaction (to/from device).
*
* This function implements the pci_map_single function.
*/
static dma_addr_t
-ccio_map_single(struct device *dev, void *addr, size_t size,
+ccio_map_single(struct device *dev, phys_addr_t addr, size_t size,
enum dma_data_direction direction)
{
int idx;
@@ -738,16 +719,18 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
unsigned long flags;
dma_addr_t iovp;
dma_addr_t offset;
- u64 *pdir_start;
+ __le64 *pdir_start;
unsigned long hint = hint_lookup[(int)direction];
BUG_ON(!dev);
ioc = GET_IOC(dev);
+ if (!ioc)
+ return DMA_MAPPING_ERROR;
BUG_ON(size <= 0);
/* save offset bits */
- offset = ((unsigned long) addr) & ~IOVP_MASK;
+ offset = offset_in_page(addr);
/* round up to nearest IOVP_SIZE */
size = ALIGN(size + offset, IOVP_SIZE);
@@ -763,15 +746,15 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
pdir_start = &(ioc->pdir_base[idx]);
- DBG_RUN("%s() 0x%p -> 0x%lx size: %0x%x\n",
- __func__, addr, (long)iovp | offset, size);
+ DBG_RUN("%s() %pa -> %#lx size: %zu\n",
+ __func__, &addr, (long)(iovp | offset), size);
/* If not cacheline aligned, force SAFE_DMA on the whole mess */
- if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES))
+ if ((size % L1_CACHE_BYTES) || (addr % L1_CACHE_BYTES))
hint |= HINT_SAFE_DMA;
while(size > 0) {
- ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long)addr, hint);
+ ccio_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, hint);
DBG_RUN(" pdir %p %08x%08x\n",
pdir_start,
@@ -788,18 +771,29 @@ ccio_map_single(struct device *dev, void *addr, size_t size,
return CCIO_IOVA(iovp, offset);
}
+
+static dma_addr_t
+ccio_map_phys(struct device *dev, phys_addr_t phys, size_t size,
+ enum dma_data_direction direction, unsigned long attrs)
+{
+ if (unlikely(attrs & DMA_ATTR_MMIO))
+ return DMA_MAPPING_ERROR;
+
+ return ccio_map_single(dev, phys, size, direction);
+}
+
+
/**
- * ccio_unmap_single - Unmap an address range from the IOMMU.
+ * ccio_unmap_phys - Unmap an address range from the IOMMU.
* @dev: The PCI device.
- * @addr: The start address of the DMA region.
+ * @iova: The start address of the DMA region.
* @size: The length of the DMA region.
* @direction: The direction of the DMA transaction (to/from device).
- *
- * This function implements the pci_unmap_single function.
+ * @attrs: attributes
*/
static void
-ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
- enum dma_data_direction direction)
+ccio_unmap_phys(struct device *dev, dma_addr_t iova, size_t size,
+ enum dma_data_direction direction, unsigned long attrs)
{
struct ioc *ioc;
unsigned long flags;
@@ -807,8 +801,12 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
BUG_ON(!dev);
ioc = GET_IOC(dev);
+ if (!ioc) {
+ WARN_ON(!ioc);
+ return;
+ }
- DBG_RUN("%s() iovp 0x%lx/%x\n",
+ DBG_RUN("%s() iovp %#lx/%zx\n",
__func__, (long)iova, size);
iova ^= offset; /* clear offset bits */
@@ -828,17 +826,20 @@ ccio_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
}
/**
- * ccio_alloc_consistent - Allocate a consistent DMA mapping.
+ * ccio_alloc - Allocate a consistent DMA mapping.
* @dev: The PCI device.
* @size: The length of the DMA region.
* @dma_handle: The DMA address handed back to the device (not the cpu).
+ * @flag: allocation flags
+ * @attrs: attributes
*
* This function implements the pci_alloc_consistent function.
*/
static void *
-ccio_alloc_consistent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag)
+ccio_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag,
+ unsigned long attrs)
{
- void *ret;
+ void *ret;
#if 0
/* GRANT Need to establish hierarchy for non-PCI devs as well
** and then provide matching gsc_map_xxx() functions for them as well.
@@ -849,30 +850,32 @@ ccio_alloc_consistent(struct device *dev, size_t size, dma_addr_t *dma_handle, g
return 0;
}
#endif
- ret = (void *) __get_free_pages(flag, get_order(size));
+ ret = (void *) __get_free_pages(flag, get_order(size));
if (ret) {
memset(ret, 0, size);
- *dma_handle = ccio_map_single(dev, ret, size, PCI_DMA_BIDIRECTIONAL);
+ *dma_handle = ccio_map_single(dev, virt_to_phys(ret), size,
+ DMA_BIDIRECTIONAL);
}
return ret;
}
/**
- * ccio_free_consistent - Free a consistent DMA mapping.
+ * ccio_free - Free a consistent DMA mapping.
* @dev: The PCI device.
* @size: The length of the DMA region.
* @cpu_addr: The cpu address returned from the ccio_alloc_consistent.
* @dma_handle: The device address returned from the ccio_alloc_consistent.
+ * @attrs: attributes
*
* This function implements the pci_free_consistent function.
*/
static void
-ccio_free_consistent(struct device *dev, size_t size, void *cpu_addr,
- dma_addr_t dma_handle)
+ccio_free(struct device *dev, size_t size, void *cpu_addr,
+ dma_addr_t dma_handle, unsigned long attrs)
{
- ccio_unmap_single(dev, dma_handle, size, 0);
+ ccio_unmap_phys(dev, dma_handle, size, 0, 0);
free_pages((unsigned long)cpu_addr, get_order(size));
}
@@ -894,12 +897,13 @@ ccio_free_consistent(struct device *dev, size_t size, void *cpu_addr,
* @sglist: The scatter/gather list to be mapped in the IOMMU.
* @nents: The number of entries in the scatter/gather list.
* @direction: The direction of the DMA transaction (to/from device).
+ * @attrs: attributes
*
* This function implements the pci_map_sg function.
*/
static int
ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
- enum dma_data_direction direction)
+ enum dma_data_direction direction, unsigned long attrs)
{
struct ioc *ioc;
int coalesced, filled = 0;
@@ -910,13 +914,15 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
BUG_ON(!dev);
ioc = GET_IOC(dev);
+ if (!ioc)
+ return -EINVAL;
DBG_RUN_SG("%s() START %d entries\n", __func__, nents);
/* Fast path single entry scatterlists. */
if (nents == 1) {
sg_dma_address(sglist) = ccio_map_single(dev,
- (void *)sg_virt_addr(sglist), sglist->length,
+ sg_phys(sglist), sglist->length,
direction);
sg_dma_len(sglist) = sglist->length;
return 1;
@@ -971,57 +977,60 @@ ccio_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
* @sglist: The scatter/gather list to be unmapped from the IOMMU.
* @nents: The number of entries in the scatter/gather list.
* @direction: The direction of the DMA transaction (to/from device).
+ * @attrs: attributes
*
* This function implements the pci_unmap_sg function.
*/
static void
ccio_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
- enum dma_data_direction direction)
+ enum dma_data_direction direction, unsigned long attrs)
{
struct ioc *ioc;
BUG_ON(!dev);
ioc = GET_IOC(dev);
+ if (!ioc) {
+ WARN_ON(!ioc);
+ return;
+ }
- DBG_RUN_SG("%s() START %d entries, %08lx,%x\n",
- __func__, nents, sg_virt_addr(sglist), sglist->length);
+ DBG_RUN_SG("%s() START %d entries, %p,%x\n",
+ __func__, nents, sg_virt(sglist), sglist->length);
#ifdef CCIO_COLLECT_STATS
ioc->usg_calls++;
#endif
- while(sg_dma_len(sglist) && nents--) {
+ while (nents && sg_dma_len(sglist)) {
#ifdef CCIO_COLLECT_STATS
ioc->usg_pages += sg_dma_len(sglist) >> PAGE_SHIFT;
#endif
- ccio_unmap_single(dev, sg_dma_address(sglist),
- sg_dma_len(sglist), direction);
+ ccio_unmap_phys(dev, sg_dma_address(sglist),
+ sg_dma_len(sglist), direction, 0);
++sglist;
+ nents--;
}
DBG_RUN_SG("%s() DONE (nents %d)\n", __func__, nents);
}
-static struct hppa_dma_ops ccio_ops = {
+static const struct dma_map_ops ccio_ops = {
.dma_supported = ccio_dma_supported,
- .alloc_consistent = ccio_alloc_consistent,
- .alloc_noncoherent = ccio_alloc_consistent,
- .free_consistent = ccio_free_consistent,
- .map_single = ccio_map_single,
- .unmap_single = ccio_unmap_single,
- .map_sg = ccio_map_sg,
- .unmap_sg = ccio_unmap_sg,
- .dma_sync_single_for_cpu = NULL, /* NOP for U2/Uturn */
- .dma_sync_single_for_device = NULL, /* NOP for U2/Uturn */
- .dma_sync_sg_for_cpu = NULL, /* ditto */
- .dma_sync_sg_for_device = NULL, /* ditto */
+ .alloc = ccio_alloc,
+ .free = ccio_free,
+ .map_phys = ccio_map_phys,
+ .unmap_phys = ccio_unmap_phys,
+ .map_sg = ccio_map_sg,
+ .unmap_sg = ccio_unmap_sg,
+ .get_sgtable = dma_common_get_sgtable,
+ .alloc_pages_op = dma_common_alloc_pages,
+ .free_pages = dma_common_free_pages,
};
#ifdef CONFIG_PROC_FS
static int ccio_proc_info(struct seq_file *m, void *p)
{
- int len = 0;
struct ioc *ioc = ioc_list;
while (ioc != NULL) {
@@ -1031,22 +1040,22 @@ static int ccio_proc_info(struct seq_file *m, void *p)
int j;
#endif
- len += seq_printf(m, "%s\n", ioc->name);
+ seq_printf(m, "%s\n", ioc->name);
- len += seq_printf(m, "Cujo 2.0 bug : %s\n",
- (ioc->cujo20_bug ? "yes" : "no"));
+ seq_printf(m, "Cujo 2.0 bug : %s\n",
+ (ioc->cujo20_bug ? "yes" : "no"));
- len += seq_printf(m, "IO PDIR size : %d bytes (%d entries)\n",
- total_pages * 8, total_pages);
+ seq_printf(m, "IO PDIR size : %d bytes (%d entries)\n",
+ total_pages * 8, total_pages);
#ifdef CCIO_COLLECT_STATS
- len += seq_printf(m, "IO PDIR entries : %ld free %ld used (%d%%)\n",
- total_pages - ioc->used_pages, ioc->used_pages,
- (int)(ioc->used_pages * 100 / total_pages));
+ seq_printf(m, "IO PDIR entries : %ld free %ld used (%d%%)\n",
+ total_pages - ioc->used_pages, ioc->used_pages,
+ (int)(ioc->used_pages * 100 / total_pages));
#endif
- len += seq_printf(m, "Resource bitmap : %d bytes (%d pages)\n",
- ioc->res_size, total_pages);
+ seq_printf(m, "Resource bitmap : %d bytes (%d pages)\n",
+ ioc->res_size, total_pages);
#ifdef CCIO_COLLECT_STATS
min = max = ioc->avg_search[0];
@@ -1058,26 +1067,26 @@ static int ccio_proc_info(struct seq_file *m, void *p)
min = ioc->avg_search[j];
}
avg /= CCIO_SEARCH_SAMPLE;
- len += seq_printf(m, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
- min, avg, max);
+ seq_printf(m, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
+ min, avg, max);
- len += seq_printf(m, "pci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n",
- ioc->msingle_calls, ioc->msingle_pages,
- (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls));
+ seq_printf(m, "pci_map_single(): %8ld calls %8ld pages (avg %d/1000)\n",
+ ioc->msingle_calls, ioc->msingle_pages,
+ (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls));
- /* KLUGE - unmap_sg calls unmap_single for each mapped page */
+ /* KLUGE - unmap_sg calls unmap_phys for each mapped page */
min = ioc->usingle_calls - ioc->usg_calls;
max = ioc->usingle_pages - ioc->usg_pages;
- len += seq_printf(m, "pci_unmap_single: %8ld calls %8ld pages (avg %d/1000)\n",
- min, max, (int)((max * 1000)/min));
-
- len += seq_printf(m, "pci_map_sg() : %8ld calls %8ld pages (avg %d/1000)\n",
- ioc->msg_calls, ioc->msg_pages,
- (int)((ioc->msg_pages * 1000)/ioc->msg_calls));
-
- len += seq_printf(m, "pci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n\n\n",
- ioc->usg_calls, ioc->usg_pages,
- (int)((ioc->usg_pages * 1000)/ioc->usg_calls));
+ seq_printf(m, "pci_unmap_single: %8ld calls %8ld pages (avg %d/1000)\n",
+ min, max, (int)((max * 1000)/min));
+
+ seq_printf(m, "pci_map_sg() : %8ld calls %8ld pages (avg %d/1000)\n",
+ ioc->msg_calls, ioc->msg_pages,
+ (int)((ioc->msg_pages * 1000)/ioc->msg_calls));
+
+ seq_printf(m, "pci_unmap_sg() : %8ld calls %8ld pages (avg %d/1000)\n\n\n",
+ ioc->usg_calls, ioc->usg_pages,
+ (int)((ioc->usg_pages * 1000)/ioc->usg_calls));
#endif /* CCIO_COLLECT_STATS */
ioc = ioc->next;
@@ -1086,54 +1095,20 @@ static int ccio_proc_info(struct seq_file *m, void *p)
return 0;
}
-static int ccio_proc_info_open(struct inode *inode, struct file *file)
-{
- return single_open(file, &ccio_proc_info, NULL);
-}
-
-static const struct file_operations ccio_proc_info_fops = {
- .owner = THIS_MODULE,
- .open = ccio_proc_info_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static int ccio_proc_bitmap_info(struct seq_file *m, void *p)
{
- int len = 0;
struct ioc *ioc = ioc_list;
while (ioc != NULL) {
- u32 *res_ptr = (u32 *)ioc->res_map;
- int j;
-
- for (j = 0; j < (ioc->res_size / sizeof(u32)); j++) {
- if ((j & 7) == 0)
- len += seq_puts(m, "\n ");
- len += seq_printf(m, "%08x", *res_ptr);
- res_ptr++;
- }
- len += seq_puts(m, "\n\n");
+ seq_hex_dump(m, " ", DUMP_PREFIX_NONE, 32, 4, ioc->res_map,
+ ioc->res_size, false);
+ seq_putc(m, '\n');
ioc = ioc->next;
break; /* XXX - remove me */
}
return 0;
}
-
-static int ccio_proc_bitmap_open(struct inode *inode, struct file *file)
-{
- return single_open(file, &ccio_proc_bitmap_info, NULL);
-}
-
-static const struct file_operations ccio_proc_bitmap_fops = {
- .owner = THIS_MODULE,
- .open = ccio_proc_bitmap_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
#endif /* CONFIG_PROC_FS */
/**
@@ -1181,7 +1156,7 @@ void * ccio_get_iommu(const struct parisc_device *dev)
* to/from certain pages. To avoid this happening, we mark these pages
* as `used', and ensure that nothing will try to allocate from them.
*/
-void ccio_cujo20_fixup(struct parisc_device *cujo, u32 iovp)
+void __init ccio_cujo20_fixup(struct parisc_device *cujo, u32 iovp)
{
unsigned int idx;
struct parisc_device *dev = parisc_parent(cujo);
@@ -1193,7 +1168,7 @@ void ccio_cujo20_fixup(struct parisc_device *cujo, u32 iovp)
idx = PDIR_INDEX(iovp) >> 3;
while (idx < ioc->res_size) {
- res_ptr[idx] |= 0xff;
+ res_ptr[idx] |= 0xff;
idx += PDIR_INDEX(CUJO_20_STEP) >> 3;
}
}
@@ -1227,7 +1202,7 @@ ccio_get_iotlb_size(struct parisc_device *dev)
#endif /* 0 */
/* We *can't* support JAVA (T600). Venture there at your own risk. */
-static const struct parisc_device_id ccio_tbl[] = {
+static const struct parisc_device_id ccio_tbl[] __initconst = {
{ HPHW_IOA, HVERSION_REV_ANY_ID, U2_IOA_RUNWAY, 0xb }, /* U2 */
{ HPHW_IOA, HVERSION_REV_ANY_ID, UTURN_IOA_RUNWAY, 0xb }, /* UTurn */
{ 0, }
@@ -1235,7 +1210,7 @@ static const struct parisc_device_id ccio_tbl[] = {
static int ccio_probe(struct parisc_device *dev);
-static struct parisc_driver ccio_driver = {
+static struct parisc_driver ccio_driver __refdata = {
.name = "ccio",
.id_table = ccio_tbl,
.probe = ccio_probe,
@@ -1249,7 +1224,7 @@ static struct parisc_driver ccio_driver = {
* I/O Page Directory, the resource map, and initalizing the
* U2/Uturn chip into virtual mode.
*/
-static void
+static void __init
ccio_ioc_init(struct ioc *ioc)
{
int i;
@@ -1267,7 +1242,7 @@ ccio_ioc_init(struct ioc *ioc)
** Hot-Plug/Removal of PCI cards. (aka PCI OLARD).
*/
- iova_space_size = (u32) (totalram_pages / count_parisc_driver(&ccio_driver));
+ iova_space_size = (u32) (totalram_pages() / count_parisc_driver(&ccio_driver));
/* limit IOVA space size to 1MB-1GB */
@@ -1306,11 +1281,11 @@ ccio_ioc_init(struct ioc *ioc)
DBG_INIT("%s() hpa 0x%p mem %luMB IOV %dMB (%d bits)\n",
__func__, ioc->ioc_regs,
- (unsigned long) totalram_pages >> (20 - PAGE_SHIFT),
+ (unsigned long) totalram_pages() >> (20 - PAGE_SHIFT),
iova_space_size>>20,
iov_order + PAGE_SHIFT);
- ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL,
+ ioc->pdir_base = (__le64 *)__get_free_pages(GFP_KERNEL,
get_order(ioc->pdir_size));
if(NULL == ioc->pdir_base) {
panic("%s() could not allocate I/O Page Table\n", __func__);
@@ -1321,7 +1296,7 @@ ccio_ioc_init(struct ioc *ioc)
DBG_INIT(" base %p\n", ioc->pdir_base);
/* resource map size dictated by pdir_size */
- ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3;
+ ioc->res_size = (ioc->pdir_size / sizeof(u64)) >> 3;
DBG_INIT("%s() res_size 0x%x\n", __func__, ioc->res_size);
ioc->res_map = (u8 *)__get_free_pages(GFP_KERNEL,
@@ -1403,15 +1378,17 @@ ccio_init_resource(struct resource *res, char *name, void __iomem *ioaddr)
}
}
-static void __init ccio_init_resources(struct ioc *ioc)
+static int __init ccio_init_resources(struct ioc *ioc)
{
struct resource *res = ioc->mmio_region;
char *name = kmalloc(14, GFP_KERNEL);
-
+ if (unlikely(!name))
+ return -ENOMEM;
snprintf(name, 14, "GSC Bus [%d/]", ioc->hw_path);
ccio_init_resource(res, name, &ioc->ioc_regs->io_io_low);
ccio_init_resource(res + 1, name, &ioc->ioc_regs->io_io_low_hv);
+ return 0;
}
static int new_ioc_area(struct resource *res, unsigned long size,
@@ -1541,11 +1518,12 @@ static int __init ccio_probe(struct parisc_device *dev)
{
int i;
struct ioc *ioc, **ioc_p = &ioc_list;
+ struct pci_hba_data *hba;
ioc = kzalloc(sizeof(struct ioc), GFP_KERNEL);
if (ioc == NULL) {
printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");
- return 1;
+ return -ENOMEM;
}
ioc->name = dev->id.hversion == U2_IOA_RUNWAY ? "U2" : "UTurn";
@@ -1559,27 +1537,40 @@ static int __init ccio_probe(struct parisc_device *dev)
*ioc_p = ioc;
ioc->hw_path = dev->hw_path;
- ioc->ioc_regs = ioremap_nocache(dev->hpa.start, 4096);
+ ioc->ioc_regs = ioremap(dev->hpa.start, 4096);
+ if (!ioc->ioc_regs) {
+ kfree(ioc);
+ return -ENOMEM;
+ }
ccio_ioc_init(ioc);
- ccio_init_resources(ioc);
+ if (ccio_init_resources(ioc)) {
+ iounmap(ioc->ioc_regs);
+ kfree(ioc);
+ return -ENOMEM;
+ }
hppa_dma_ops = &ccio_ops;
- dev->dev.platform_data = kzalloc(sizeof(struct pci_hba_data), GFP_KERNEL);
+ hba = kzalloc(sizeof(*hba), GFP_KERNEL);
/* if this fails, no I/O cards will work, so may as well bug */
- BUG_ON(dev->dev.platform_data == NULL);
- HBA_DATA(dev->dev.platform_data)->iommu = ioc;
+ BUG_ON(hba == NULL);
+
+ hba->iommu = ioc;
+ dev->dev.platform_data = hba;
#ifdef CONFIG_PROC_FS
if (ioc_count == 0) {
- proc_create(MODULE_NAME, 0, proc_runway_root,
- &ccio_proc_info_fops);
- proc_create(MODULE_NAME"-bitmap", 0, proc_runway_root,
- &ccio_proc_bitmap_fops);
+ struct proc_dir_entry *runway;
+
+ runway = proc_mkdir("bus/runway", NULL);
+ if (runway) {
+ proc_create_single(MODULE_NAME, 0, runway,
+ ccio_proc_info);
+ proc_create_single(MODULE_NAME"-bitmap", 0, runway,
+ ccio_proc_bitmap_info);
+ }
}
#endif
ioc_count++;
-
- parisc_has_iommu();
return 0;
}
@@ -1588,8 +1579,8 @@ static int __init ccio_probe(struct parisc_device *dev)
*
* Register this driver.
*/
-void __init ccio_init(void)
+static int __init ccio_init(void)
{
- register_parisc_driver(&ccio_driver);
+ return register_parisc_driver(&ccio_driver);
}
-
+arch_initcall(ccio_init);
diff --git a/drivers/parisc/ccio-rm-dma.c b/drivers/parisc/ccio-rm-dma.c
deleted file mode 100644
index f78f6f1aef47..000000000000
--- a/drivers/parisc/ccio-rm-dma.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * ccio-rm-dma.c:
- * DMA management routines for first generation cache-coherent machines.
- * "Real Mode" operation refers to U2/Uturn chip operation. The chip
- * can perform coherency checks w/o using the I/O MMU. That's all we
- * need until support for more than 4GB phys mem is needed.
- *
- * This is the trivial case - basically what x86 does.
- *
- * Drawbacks of using Real Mode are:
- * o outbound DMA is slower since one isn't using the prefetching
- * U2 can do for outbound DMA.
- * o Ability to do scatter/gather in HW is also lost.
- * o only known to work with PCX-W processor. (eg C360)
- * (PCX-U/U+ are not coherent with U2 in real mode.)
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- *
- * Original version/author:
- * CVSROOT=:pserver:anonymous@198.186.203.37:/cvsroot/linux-parisc
- * cvs -z3 co linux/arch/parisc/kernel/dma-rm.c
- *
- * (C) Copyright 2000 Philipp Rumpf <prumpf@tux.org>
- *
- *
- * Adopted for The Puffin Group's parisc-linux port by Grant Grundler.
- * (C) Copyright 2000 Grant Grundler <grundler@puffin.external.hp.com>
- *
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <linux/gfp.h>
-
-#include <asm/uaccess.h>
-
-#include <asm/io.h>
-#include <asm/hardware.h>
-#include <asm/page.h>
-
-/* Only chose "ccio" since that's what HP-UX calls it....
-** Make it easier for folks to migrate from one to the other :^)
-*/
-#define MODULE_NAME "ccio"
-
-#define U2_IOA_RUNWAY 0x580
-#define U2_BC_GSC 0x501
-#define UTURN_IOA_RUNWAY 0x581
-#define UTURN_BC_GSC 0x502
-
-#define IS_U2(id) ( \
- (((id)->hw_type == HPHW_IOA) && ((id)->hversion == U2_IOA_RUNWAY)) || \
- (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == U2_BC_GSC)) \
-)
-
-#define IS_UTURN(id) ( \
- (((id)->hw_type == HPHW_IOA) && ((id)->hversion == UTURN_IOA_RUNWAY)) || \
- (((id)->hw_type == HPHW_BCPORT) && ((id)->hversion == UTURN_BC_GSC)) \
-)
-
-static int ccio_dma_supported( struct pci_dev *dev, u64 mask)
-{
- if (dev == NULL) {
- printk(KERN_ERR MODULE_NAME ": EISA/ISA/et al not supported\n");
- BUG();
- return(0);
- }
-
- /* only support 32-bit devices (ie PCI/GSC) */
- return((int) (mask >= 0xffffffffUL));
-}
-
-
-static void *ccio_alloc_consistent(struct pci_dev *dev, size_t size,
- dma_addr_t *handle)
-{
- void *ret;
-
- ret = (void *)__get_free_pages(GFP_ATOMIC, get_order(size));
-
- if (ret != NULL) {
- memset(ret, 0, size);
- *handle = virt_to_phys(ret);
- }
- return ret;
-}
-
-static void ccio_free_consistent(struct pci_dev *dev, size_t size,
- void *vaddr, dma_addr_t handle)
-{
- free_pages((unsigned long)vaddr, get_order(size));
-}
-
-static dma_addr_t ccio_map_single(struct pci_dev *dev, void *ptr, size_t size,
- int direction)
-{
- return virt_to_phys(ptr);
-}
-
-static void ccio_unmap_single(struct pci_dev *dev, dma_addr_t dma_addr,
- size_t size, int direction)
-{
- /* Nothing to do */
-}
-
-
-static int ccio_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
-{
- int tmp = nents;
-
- /* KISS: map each buffer separately. */
- while (nents) {
- sg_dma_address(sglist) = ccio_map_single(dev, sglist->address, sglist->length, direction);
- sg_dma_len(sglist) = sglist->length;
- nents--;
- sglist++;
- }
-
- return tmp;
-}
-
-
-static void ccio_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents, int direction)
-{
-#if 0
- while (nents) {
- ccio_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
- nents--;
- sglist++;
- }
- return;
-#else
- /* Do nothing (copied from current ccio_unmap_single() :^) */
-#endif
-}
-
-
-static struct pci_dma_ops ccio_ops = {
- ccio_dma_supported,
- ccio_alloc_consistent,
- ccio_free_consistent,
- ccio_map_single,
- ccio_unmap_single,
- ccio_map_sg,
- ccio_unmap_sg,
- NULL, /* dma_sync_single_for_cpu : NOP for U2 */
- NULL, /* dma_sync_single_for_device : NOP for U2 */
- NULL, /* dma_sync_sg_for_cpu : ditto */
- NULL, /* dma_sync_sg_for_device : ditto */
-};
-
-
-/*
-** Determine if u2 should claim this chip (return 0) or not (return 1).
-** If so, initialize the chip and tell other partners in crime they
-** have work to do.
-*/
-static int
-ccio_probe(struct parisc_device *dev)
-{
- printk(KERN_INFO "%s found %s at 0x%lx\n", MODULE_NAME,
- dev->id.hversion == U2_BC_GSC ? "U2" : "UTurn",
- dev->hpa.start);
-
-/*
-** FIXME - should check U2 registers to verify it's really running
-** in "Real Mode".
-*/
-
-#if 0
-/* will need this for "Virtual Mode" operation */
- ccio_hw_init(ccio_dev);
- ccio_common_init(ccio_dev);
-#endif
- hppa_dma_ops = &ccio_ops;
- return 0;
-}
-
-static struct parisc_device_id ccio_tbl[] = {
- { HPHW_BCPORT, HVERSION_REV_ANY_ID, U2_BC_GSC, 0xc },
- { HPHW_BCPORT, HVERSION_REV_ANY_ID, UTURN_BC_GSC, 0xc },
- { 0, }
-};
-
-static struct parisc_driver ccio_driver = {
- .name = "U2/Uturn",
- .id_table = ccio_tbl,
- .probe = ccio_probe,
-};
-
-void __init ccio_init(void)
-{
- register_parisc_driver(&ccio_driver);
-}
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 9eae9834bcc7..01a50a051296 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
** DINO manager
**
@@ -5,12 +6,8 @@
** (c) Copyright 1999 SuSE GmbH
** (c) Copyright 1999,2000 Hewlett-Packard Company
** (c) Copyright 2000 Grant Grundler
-** (c) Copyright 2006 Helge Deller
+** (c) Copyright 2006-2019 Helge Deller
**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
**
** This module provides access to Dino PCI bus (config/IOport spaces)
** and helps manage Dino IRQ lines.
@@ -59,6 +56,7 @@
#include <asm/hardware.h>
#include "gsc.h"
+#include "iommu.h"
#undef DINO_DEBUG
@@ -144,18 +142,18 @@ struct dino_device
{
struct pci_hba_data hba; /* 'C' inheritance - must be first */
spinlock_t dinosaur_pen;
- unsigned long txn_addr; /* EIR addr to generate interrupt */
- u32 txn_data; /* EIR data assign to each dino */
u32 imr; /* IRQ's which are enabled */
+ struct gsc_irq gsc_irq;
int global_irq[DINO_LOCAL_IRQS]; /* map IMR bit to global irq */
#ifdef DINO_DEBUG
unsigned int dino_irr0; /* save most recent IRQ line stat */
#endif
};
-/* Looks nice and keeps the compiler happy */
-#define DINO_DEV(d) ((struct dino_device *) d)
-
+static inline struct dino_device *DINO_DEV(struct pci_hba_data *hba)
+{
+ return container_of(hba, struct dino_device, hba);
+}
/*
* Dino Configuration Space Accessor Functions
@@ -300,7 +298,7 @@ static void dino_mask_irq(struct irq_data *d)
struct dino_device *dino_dev = irq_data_get_irq_chip_data(d);
int local_irq = gsc_find_local_irq(d->irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
- DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, d->irq);
+ DBG(KERN_WARNING "%s(0x%px, %d)\n", __func__, dino_dev, d->irq);
/* Clear the matching bit in the IMR register */
dino_dev->imr &= ~(DINO_MASK_IRQ(local_irq));
@@ -313,7 +311,7 @@ static void dino_unmask_irq(struct irq_data *d)
int local_irq = gsc_find_local_irq(d->irq, dino_dev->global_irq, DINO_LOCAL_IRQS);
u32 tmp;
- DBG(KERN_WARNING "%s(0x%p, %d)\n", __func__, dino_dev, d->irq);
+ DBG(KERN_WARNING "%s(0x%px, %d)\n", __func__, dino_dev, d->irq);
/*
** clear pending IRQ bits
@@ -340,14 +338,43 @@ static void dino_unmask_irq(struct irq_data *d)
if (tmp & DINO_MASK_IRQ(local_irq)) {
DBG(KERN_WARNING "%s(): IRQ asserted! (ILR 0x%x)\n",
__func__, tmp);
- gsc_writel(dino_dev->txn_data, dino_dev->txn_addr);
+ gsc_writel(dino_dev->gsc_irq.txn_data, dino_dev->gsc_irq.txn_addr);
}
}
+#ifdef CONFIG_SMP
+static int dino_set_affinity_irq(struct irq_data *d, const struct cpumask *dest,
+ bool force)
+{
+ struct dino_device *dino_dev = irq_data_get_irq_chip_data(d);
+ struct cpumask tmask;
+ int cpu_irq;
+ u32 eim;
+
+ if (!cpumask_and(&tmask, dest, cpu_online_mask))
+ return -EINVAL;
+
+ cpu_irq = cpu_check_affinity(d, &tmask);
+ if (cpu_irq < 0)
+ return cpu_irq;
+
+ dino_dev->gsc_irq.txn_addr = txn_affinity_addr(d->irq, cpu_irq);
+ eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data;
+ __raw_writel(eim, dino_dev->hba.base_addr+DINO_IAR0);
+
+ irq_data_update_effective_affinity(d, &tmask);
+
+ return IRQ_SET_MASK_OK;
+}
+#endif
+
static struct irq_chip dino_interrupt_type = {
.name = "GSC-PCI",
.irq_unmask = dino_unmask_irq,
.irq_mask = dino_mask_irq,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = dino_set_affinity_irq,
+#endif
};
@@ -379,7 +406,7 @@ ilr_again:
DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n",
__func__, irq, intr_dev, mask);
generic_handle_irq(irq);
- mask &= ~(1 << local_irq);
+ mask &= ~DINO_MASK_IRQ(local_irq);
} while (mask);
/* Support for level triggered IRQ lines.
@@ -393,9 +420,8 @@ ilr_again:
if (mask) {
if (--ilr_loop > 0)
goto ilr_again;
- printk(KERN_ERR "Dino 0x%p: stuck interrupt %d\n",
+ pr_warn_ratelimited("Dino 0x%px: stuck interrupt %d\n",
dino_dev->hba.base_addr, mask);
- return IRQ_NONE;
}
return IRQ_HANDLED;
}
@@ -439,6 +465,30 @@ static void quirk_cirrus_cardbus(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_CIRRUS, PCI_DEVICE_ID_CIRRUS_6832, quirk_cirrus_cardbus );
+#ifdef CONFIG_TULIP
+/* Check if PCI device is behind a Card-mode Dino. */
+static int pci_dev_is_behind_card_dino(struct pci_dev *dev)
+{
+ struct dino_device *dino_dev;
+
+ dino_dev = DINO_DEV(parisc_walk_tree(dev->bus->bridge));
+ return is_card_dino(&dino_dev->hba.dev->id);
+}
+
+static void pci_fixup_tulip(struct pci_dev *dev)
+{
+ if (!pci_dev_is_behind_card_dino(dev))
+ return;
+ if (!(pci_resource_flags(dev, 1) & IORESOURCE_MEM))
+ return;
+ pr_warn("%s: HP HSC-PCI Cards with card-mode Dino not yet supported.\n",
+ pci_name(dev));
+ /* Disable this card by zeroing the PCI resources */
+ memset(&dev->resource[0], 0, sizeof(dev->resource[0]));
+ memset(&dev->resource[1], 0, sizeof(dev->resource[1]));
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_DEC, PCI_ANY_ID, pci_fixup_tulip);
+#endif /* CONFIG_TULIP */
static void __init
dino_bios_init(void)
@@ -550,7 +600,7 @@ dino_fixup_bus(struct pci_bus *bus)
struct pci_dev *dev;
struct dino_device *dino_dev = DINO_DEV(parisc_walk_tree(bus->bridge));
- DBG(KERN_WARNING "%s(0x%p) bus %d platform_data 0x%p\n",
+ DBG(KERN_WARNING "%s(0x%px) bus %d platform_data 0x%px\n",
__func__, bus, bus->busn_res.start,
bus->bridge->platform_data);
@@ -599,8 +649,10 @@ dino_fixup_bus(struct pci_bus *bus)
** P2PB's only have 2 BARs, no IRQs.
** I'd like to just ignore them for now.
*/
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ pcibios_init_bridge(dev);
continue;
+ }
/* null out the ROM resource if there is one (we don't
* care about an expansion rom on parisc, since it
@@ -782,7 +834,6 @@ static int __init dino_common_init(struct parisc_device *dev,
{
int status;
u32 eim;
- struct gsc_irq gsc_irq;
struct resource *res;
pcibios_register_hba(&dino_dev->hba);
@@ -797,10 +848,8 @@ static int __init dino_common_init(struct parisc_device *dev,
** still only has 11 IRQ input lines - just map some of them
** to a different processor.
*/
- dev->irq = gsc_alloc_irq(&gsc_irq);
- dino_dev->txn_addr = gsc_irq.txn_addr;
- dino_dev->txn_data = gsc_irq.txn_data;
- eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+ dev->irq = gsc_alloc_irq(&dino_dev->gsc_irq);
+ eim = ((u32) dino_dev->gsc_irq.txn_addr) | dino_dev->gsc_irq.txn_data;
/*
** Dino needs a PA "IRQ" to get a processor's attention.
@@ -849,7 +898,7 @@ static int __init dino_common_init(struct parisc_device *dev,
res->flags = IORESOURCE_IO; /* do not mark it busy ! */
if (request_resource(&ioport_resource, res) < 0) {
printk(KERN_ERR "%s: request I/O Port region failed "
- "0x%lx/%lx (hpa 0x%p)\n",
+ "0x%lx/%lx (hpa 0x%px)\n",
name, (unsigned long)res->start, (unsigned long)res->end,
dino_dev->hba.base_addr);
return 1;
@@ -863,20 +912,18 @@ static int __init dino_common_init(struct parisc_device *dev,
#define CUJO_RAVEN_BADPAGE 0x01003000UL
#define CUJO_FIREHAWK_BADPAGE 0x01607000UL
-static const char *dino_vers[] = {
+static const char dino_vers[][4] = {
"2.0",
"2.1",
"3.0",
"3.1"
};
-static const char *cujo_vers[] = {
+static const char cujo_vers[][4] = {
"1.0",
"2.0"
};
-void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp);
-
/*
** Determine if dino should claim this chip (return 0) or not (return 1).
** If so, initialize the chip appropriately (card-mode vs bridge mode).
@@ -913,7 +960,7 @@ static int __init dino_probe(struct parisc_device *dev)
printk("%s version %s found at 0x%lx\n", name, version, hpa);
if (!request_mem_region(hpa, PAGE_SIZE, name)) {
- printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%ld)!\n",
+ printk(KERN_ERR "DINO: Hey! Someone took my MMIO space (0x%lx)!\n",
hpa);
return 1;
}
@@ -950,8 +997,8 @@ static int __init dino_probe(struct parisc_device *dev)
}
dino_dev->hba.dev = dev;
- dino_dev->hba.base_addr = ioremap_nocache(hpa, 4096);
- dino_dev->hba.lmmio_space_offset = 0; /* CPU addrs == bus addrs */
+ dino_dev->hba.base_addr = ioremap(hpa, 4096);
+ dino_dev->hba.lmmio_space_offset = PCI_F_EXTEND;
spin_lock_init(&dino_dev->dinosaur_pen);
dino_dev->hba.iommu = ccio_get_iommu(dev);
@@ -1017,7 +1064,7 @@ static int __init dino_probe(struct parisc_device *dev)
* and 725 firmware misreport it as 0x08080 for no adequately explained
* reason.
*/
-static struct parisc_device_id dino_tbl[] = {
+static const struct parisc_device_id dino_tbl[] __initconst = {
{ HPHW_A_DMA, HVERSION_REV_ANY_ID, 0x004, 0x0009D },/* Card-mode Dino */
{ HPHW_A_DMA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x08080 }, /* XXX */
{ HPHW_BRIDGE, HVERSION_REV_ANY_ID, 0x680, 0xa }, /* Bridge-mode Dino */
@@ -1026,7 +1073,7 @@ static struct parisc_device_id dino_tbl[] = {
{ 0, }
};
-static struct parisc_driver dino_driver = {
+static struct parisc_driver dino_driver __refdata = {
.name = "dino",
.id_table = dino_tbl,
.probe = dino_probe,
@@ -1037,9 +1084,8 @@ static struct parisc_driver dino_driver = {
* This is the only routine which is NOT static.
* Must be called exactly once before pci_init().
*/
-int __init dino_init(void)
+static int __init dino_init(void)
{
- register_parisc_driver(&dino_driver);
- return 0;
+ return register_parisc_driver(&dino_driver);
}
-
+arch_initcall(dino_init);
diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
index 103095bbe8c0..9eab974e6baf 100644
--- a/drivers/parisc/eisa.c
+++ b/drivers/parisc/eisa.c
@@ -1,11 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* eisa.c - provide support for EISA adapters in PA-RISC machines
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
* Copyright (c) 2001 Daniel Engstrom <5116@telia.com>
*
@@ -14,16 +10,15 @@
* Wax ASIC also includes a PS/2 and RS-232 controller, but those are
* dealt with elsewhere; this file is concerned only with the EISA portions
* of Wax.
- *
- *
+ *
* HINT:
* -----
* To allow an ISA card to work properly in the EISA slot you need to
- * set an edge trigger level. This may be done on the palo command line
- * by adding the kernel parameter "eisa_irq_edge=n,n2,[...]]", with
+ * set an edge trigger level. This may be done on the palo command line
+ * by adding the kernel parameter "eisa_irq_edge=n,n2,[...]]", with
* n and n2 as the irq levels you want to use.
- *
- * Example: "eisa_irq_edge=10,11" allows ISA cards to operate at
+ *
+ * Example: "eisa_irq_edge=10,11" allows ISA cards to operate at
* irq levels 10 and 11.
*/
@@ -45,10 +40,12 @@
#include <asm/eisa_bus.h>
#include <asm/eisa_eeprom.h>
+#include "iommu.h"
+
#if 0
-#define EISA_DBG(msg, arg... ) printk(KERN_DEBUG "eisa: " msg , ## arg )
+#define EISA_DBG(msg, arg...) printk(KERN_DEBUG "eisa: " msg, ## arg)
#else
-#define EISA_DBG(msg, arg... )
+#define EISA_DBG(msg, arg...)
#endif
#define SNAKES_EEPROM_BASE_ADDR 0xF0810400
@@ -108,7 +105,7 @@ void eisa_out8(unsigned char data, unsigned short port)
void eisa_out16(unsigned short data, unsigned short port)
{
- if (EISA_bus)
+ if (EISA_bus)
gsc_writew(cpu_to_le16(data), eisa_permute(port));
}
@@ -135,9 +132,9 @@ static int master_mask;
static int slave_mask;
/* the trig level can be set with the
- * eisa_irq_edge=n,n,n commandline parameter
- * We should really read this from the EEPROM
- * in the furure.
+ * eisa_irq_edge=n,n,n commandline parameter
+ * We should really read this from the EEPROM
+ * in the furure.
*/
/* irq 13,8,2,1,0 must be edge */
static unsigned int eisa_irq_level __read_mostly; /* default to edge triggered */
@@ -170,7 +167,7 @@ static void eisa_unmask_irq(struct irq_data *d)
unsigned int irq = d->irq;
unsigned long flags;
EISA_DBG("enable irq %d\n", irq);
-
+
spin_lock_irqsave(&eisa_irq_lock, flags);
if (irq & 8) {
slave_mask &= ~(1 << (irq&7));
@@ -194,7 +191,7 @@ static irqreturn_t eisa_irq(int wax_irq, void *intr_dev)
{
int irq = gsc_readb(0xfc01f000); /* EISA supports 16 irqs */
unsigned long flags;
-
+
spin_lock_irqsave(&eisa_irq_lock, flags);
/* read IRR command */
eisa_out8(0x0a, 0x20);
@@ -202,31 +199,31 @@ static irqreturn_t eisa_irq(int wax_irq, void *intr_dev)
EISA_DBG("irq IAR %02x 8259-1 irr %02x 8259-2 irr %02x\n",
irq, eisa_in8(0x20), eisa_in8(0xa0));
-
+
/* read ISR command */
eisa_out8(0x0a, 0x20);
eisa_out8(0x0a, 0xa0);
EISA_DBG("irq 8259-1 isr %02x imr %02x 8259-2 isr %02x imr %02x\n",
eisa_in8(0x20), eisa_in8(0x21), eisa_in8(0xa0), eisa_in8(0xa1));
-
+
irq &= 0xf;
-
+
/* mask irq and write eoi */
if (irq & 8) {
slave_mask |= (1 << (irq&7));
eisa_out8(slave_mask, 0xa1);
eisa_out8(0x60 | (irq&7),0xa0);/* 'Specific EOI' to slave */
- eisa_out8(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */
-
+ eisa_out8(0x62, 0x20); /* 'Specific EOI' to master-IRQ2 */
+
} else {
master_mask |= (1 << (irq&7));
eisa_out8(master_mask, 0x21);
- eisa_out8(0x60|irq,0x20); /* 'Specific EOI' to master */
+ eisa_out8(0x60|irq, 0x20); /* 'Specific EOI' to master */
}
spin_unlock_irqrestore(&eisa_irq_lock, flags);
generic_handle_irq(irq);
-
+
spin_lock_irqsave(&eisa_irq_lock, flags);
/* unmask */
if (irq & 8) {
@@ -246,52 +243,47 @@ static irqreturn_t dummy_irq2_handler(int _, void *dev)
return IRQ_HANDLED;
}
-static struct irqaction irq2_action = {
- .handler = dummy_irq2_handler,
- .name = "cascade",
-};
-
static void init_eisa_pic(void)
{
unsigned long flags;
-
+
spin_lock_irqsave(&eisa_irq_lock, flags);
eisa_out8(0xff, 0x21); /* mask during init */
eisa_out8(0xff, 0xa1); /* mask during init */
-
+
/* master pic */
- eisa_out8(0x11,0x20); /* ICW1 */
- eisa_out8(0x00,0x21); /* ICW2 */
- eisa_out8(0x04,0x21); /* ICW3 */
- eisa_out8(0x01,0x21); /* ICW4 */
- eisa_out8(0x40,0x20); /* OCW2 */
-
+ eisa_out8(0x11, 0x20); /* ICW1 */
+ eisa_out8(0x00, 0x21); /* ICW2 */
+ eisa_out8(0x04, 0x21); /* ICW3 */
+ eisa_out8(0x01, 0x21); /* ICW4 */
+ eisa_out8(0x40, 0x20); /* OCW2 */
+
/* slave pic */
- eisa_out8(0x11,0xa0); /* ICW1 */
- eisa_out8(0x08,0xa1); /* ICW2 */
- eisa_out8(0x02,0xa1); /* ICW3 */
- eisa_out8(0x01,0xa1); /* ICW4 */
- eisa_out8(0x40,0xa0); /* OCW2 */
-
+ eisa_out8(0x11, 0xa0); /* ICW1 */
+ eisa_out8(0x08, 0xa1); /* ICW2 */
+ eisa_out8(0x02, 0xa1); /* ICW3 */
+ eisa_out8(0x01, 0xa1); /* ICW4 */
+ eisa_out8(0x40, 0xa0); /* OCW2 */
+
udelay(100);
-
- slave_mask = 0xff;
- master_mask = 0xfb;
+
+ slave_mask = 0xff;
+ master_mask = 0xfb;
eisa_out8(slave_mask, 0xa1); /* OCW1 */
eisa_out8(master_mask, 0x21); /* OCW1 */
-
+
/* setup trig level */
EISA_DBG("EISA edge/level %04x\n", eisa_irq_level);
-
+
eisa_out8(eisa_irq_level&0xff, 0x4d0); /* Set all irq's to edge */
- eisa_out8((eisa_irq_level >> 8) & 0xff, 0x4d1);
-
+ eisa_out8((eisa_irq_level >> 8) & 0xff, 0x4d1);
+
EISA_DBG("pic0 mask %02x\n", eisa_in8(0x21));
EISA_DBG("pic1 mask %02x\n", eisa_in8(0xa1));
EISA_DBG("pic0 edge/level %02x\n", eisa_in8(0x4d0));
EISA_DBG("pic1 edge/level %02x\n", eisa_in8(0x4d1));
-
+
spin_unlock_irqrestore(&eisa_irq_lock, flags);
}
@@ -305,7 +297,7 @@ static int __init eisa_probe(struct parisc_device *dev)
char *name = is_mongoose(dev) ? "Mongoose" : "Wax";
- printk(KERN_INFO "%s EISA Adapter found at 0x%08lx\n",
+ printk(KERN_INFO "%s EISA Adapter found at 0x%08lx\n",
name, (unsigned long)dev->hpa.start);
eisa_dev.hba.dev = dev;
@@ -334,16 +326,17 @@ static int __init eisa_probe(struct parisc_device *dev)
result = request_irq(dev->irq, eisa_irq, IRQF_SHARED, "EISA", &eisa_dev);
if (result) {
printk(KERN_ERR "EISA: request_irq failed!\n");
- return result;
+ goto error_release;
}
-
+
/* Reserve IRQ2 */
- setup_irq(2, &irq2_action);
+ if (request_irq(2, dummy_irq2_handler, 0, "cascade", NULL))
+ pr_err("Failed to request irq 2 (cascade)\n");
for (i = 0; i < 16; i++) {
irq_set_chip_and_handler(i, &eisa_interrupt_type,
handle_simple_irq);
}
-
+
EISA_bus = 1;
if (dev->num_addrs) {
@@ -357,7 +350,12 @@ static int __init eisa_probe(struct parisc_device *dev)
eisa_dev.eeprom_addr = MIRAGE_EEPROM_BASE_ADDR;
}
}
- eisa_eeprom_addr = ioremap_nocache(eisa_dev.eeprom_addr, HPEE_MAX_LENGTH);
+ eisa_eeprom_addr = ioremap(eisa_dev.eeprom_addr, HPEE_MAX_LENGTH);
+ if (!eisa_eeprom_addr) {
+ result = -ENOMEM;
+ printk(KERN_ERR "EISA: ioremap failed!\n");
+ goto error_free_irq;
+ }
result = eisa_enumerator(eisa_dev.eeprom_addr, &eisa_dev.hba.io_space,
&eisa_dev.hba.lmmio_space);
init_eisa_pic();
@@ -372,14 +370,23 @@ static int __init eisa_probe(struct parisc_device *dev)
eisa_dev.root.dma_mask = 0xffffffff; /* wild guess */
if (eisa_root_register (&eisa_dev.root)) {
printk(KERN_ERR "EISA: Failed to register EISA root\n");
- return -1;
+ result = -ENOMEM;
+ goto error_iounmap;
}
}
-
+
return 0;
+
+error_iounmap:
+ iounmap(eisa_eeprom_addr);
+error_free_irq:
+ free_irq(dev->irq, &eisa_dev);
+error_release:
+ release_resource(&eisa_dev.hba.io_space);
+ return result;
}
-static const struct parisc_device_id eisa_tbl[] = {
+static const struct parisc_device_id eisa_tbl[] __initconst = {
{ HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00076 }, /* Mongoose */
{ HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00090 }, /* Wax EISA */
{ 0, }
@@ -387,16 +394,17 @@ static const struct parisc_device_id eisa_tbl[] = {
MODULE_DEVICE_TABLE(parisc, eisa_tbl);
-static struct parisc_driver eisa_driver = {
+static struct parisc_driver eisa_driver __refdata = {
.name = "eisa_ba",
.id_table = eisa_tbl,
.probe = eisa_probe,
};
-void __init eisa_init(void)
+static int __init parisc_eisa_init(void)
{
- register_parisc_driver(&eisa_driver);
+ return register_parisc_driver(&eisa_driver);
}
+arch_initcall(parisc_eisa_init);
static unsigned int eisa_irq_configured;
@@ -404,7 +412,7 @@ void eisa_make_irq_level(int num)
{
if (eisa_irq_configured& (1<<num)) {
printk(KERN_WARNING
- "IRQ %d polarity configured twice (last to level)\n",
+ "IRQ %d polarity configured twice (last to level)\n",
num);
}
eisa_irq_level |= (1<<num); /* set the corresponding bit */
@@ -414,7 +422,7 @@ void eisa_make_irq_level(int num)
void eisa_make_irq_edge(int num)
{
if (eisa_irq_configured& (1<<num)) {
- printk(KERN_WARNING
+ printk(KERN_WARNING
"IRQ %d polarity configured twice (last to edge)\n",
num);
}
@@ -430,18 +438,18 @@ static int __init eisa_irq_setup(char *str)
EISA_DBG("IRQ setup\n");
while (cur != NULL) {
char *pe;
-
+
val = (int) simple_strtoul(cur, &pe, 0);
if (val > 15 || val < 0) {
printk(KERN_ERR "eisa: EISA irq value are 0-15\n");
continue;
}
- if (val == 2) {
+ if (val == 2) {
val = 9;
}
eisa_make_irq_edge(val); /* clear the corresponding bit */
EISA_DBG("setting IRQ %d to edge-triggered mode\n", val);
-
+
if ((cur = strchr(cur, ','))) {
cur++;
} else {
diff --git a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c
index 783906fe659a..601cbb22574f 100644
--- a/drivers/parisc/eisa_eeprom.c
+++ b/drivers/parisc/eisa_eeprom.c
@@ -1,22 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* EISA "eeprom" support routines
*
* Copyright (C) 2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
@@ -26,11 +12,9 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/eisa_eeprom.h>
-#define EISA_EEPROM_MINOR 241
-
static loff_t eisa_eeprom_llseek(struct file *file, loff_t offset, int origin)
{
return fixed_size_llseek(file, offset, origin, HPEE_MAX_LENGTH);
@@ -106,7 +90,7 @@ static int __init eisa_eeprom_init(void)
return retval;
}
- printk(KERN_INFO "EISA EEPROM at 0x%p\n", eisa_eeprom_addr);
+ printk(KERN_INFO "EISA EEPROM at 0x%px\n", eisa_eeprom_addr);
return 0;
}
diff --git a/drivers/parisc/eisa_enumerator.c b/drivers/parisc/eisa_enumerator.c
index caa153133754..f0cb31198a8f 100644
--- a/drivers/parisc/eisa_enumerator.c
+++ b/drivers/parisc/eisa_enumerator.c
@@ -1,13 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* eisa_enumerator.c - provide support for EISA adapters in PA-RISC machines
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
* Copyright (c) 2002 Daniel Engstrom <5116@telia.com>
- *
*/
#include <linux/ioport.h>
@@ -15,7 +10,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/byteorder.h>
#include <asm/eisa_bus.h>
@@ -91,14 +86,14 @@ static int configure_memory(const unsigned char *buf,
for (i=0;i<HPEE_MEMORY_MAX_ENT;i++) {
c = get_8(buf+len);
- if (NULL != (res = kmalloc(sizeof(struct resource), GFP_KERNEL))) {
+ if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) {
int result;
res->name = name;
res->start = mem_parent->start + get_24(buf+len+2);
res->end = res->start + get_16(buf+len+5)*1024;
res->flags = IORESOURCE_MEM;
- printk("memory %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
+ pr_cont("memory %pR ", res);
result = request_resource(mem_parent, res);
if (result < 0) {
printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
@@ -128,7 +123,7 @@ static int configure_irq(const unsigned char *buf)
for (i=0;i<HPEE_IRQ_MAX_ENT;i++) {
c = get_8(buf+len);
- printk("IRQ %d ", c & HPEE_IRQ_CHANNEL_MASK);
+ pr_cont("IRQ %d ", c & HPEE_IRQ_CHANNEL_MASK);
if (c & HPEE_IRQ_TRIG_LEVEL) {
eisa_make_irq_level(c & HPEE_IRQ_CHANNEL_MASK);
} else {
@@ -158,7 +153,7 @@ static int configure_dma(const unsigned char *buf)
for (i=0;i<HPEE_DMA_MAX_ENT;i++) {
c = get_8(buf+len);
- printk("DMA %d ", c&HPEE_DMA_CHANNEL_MASK);
+ pr_cont("DMA %d ", c&HPEE_DMA_CHANNEL_MASK);
/* fixme: maybe initialize the dma channel withthe timing ? */
len+=2;
if (!(c & HPEE_DMA_MORE)) {
@@ -183,12 +178,12 @@ static int configure_port(const unsigned char *buf, struct resource *io_parent,
for (i=0;i<HPEE_PORT_MAX_ENT;i++) {
c = get_8(buf+len);
- if (NULL != (res = kmalloc(sizeof(struct resource), GFP_KERNEL))) {
+ if (NULL != (res = kzalloc(sizeof(struct resource), GFP_KERNEL))) {
res->name = board;
res->start = get_16(buf+len+1);
res->end = get_16(buf+len+1)+(c&HPEE_PORT_SIZE_MASK)+1;
res->flags = IORESOURCE_IO;
- printk("ioports %lx-%lx ", (unsigned long)res->start, (unsigned long)res->end);
+ pr_cont("ioports %pR ", res);
result = request_resource(io_parent, res);
if (result < 0) {
printk(KERN_ERR "EISA Enumerator: failed to claim EISA Bus address space!\n");
@@ -357,7 +352,7 @@ static int parse_slot_config(int slot,
}
if (flags & HPEE_FUNCTION_INFO_CFG_FREE_FORM) {
/* I have no idea how to handle this */
- printk("function %d have free-form confgiuration, skipping ",
+ printk("function %d have free-form configuration, skipping ",
num_func);
pos = p0 + function_len;
continue;
@@ -398,7 +393,7 @@ static int parse_slot_config(int slot,
}
if (p0 + function_len < pos) {
- printk(KERN_ERR "eisa_enumerator: function %d length mis-match "
+ printk(KERN_ERR "eisa_enumerator: function %d length mismatch "
"got %d, expected %d\n",
num_func, pos-p0, function_len);
res=-1;
@@ -406,19 +401,19 @@ static int parse_slot_config(int slot,
}
pos = p0 + function_len;
}
- printk("\n");
+ pr_cont("\n");
if (!id_string_used) {
kfree(board);
}
if (pos != es->config_data_length) {
- printk(KERN_ERR "eisa_enumerator: config data length mis-match got %d, expected %d\n",
+ printk(KERN_ERR "eisa_enumerator: config data length mismatch got %d, expected %d\n",
pos, es->config_data_length);
res=-1;
}
if (num_func != es->num_functions) {
- printk(KERN_ERR "eisa_enumerator: number of functions mis-match got %d, expected %d\n",
+ printk(KERN_ERR "eisa_enumerator: number of functions mismatch got %d, expected %d\n",
num_func, es->num_functions);
res=-2;
}
@@ -456,7 +451,7 @@ static int init_slot(int slot, struct eeprom_eisa_slot_info *es)
}
if (es->eisa_slot_id != id) {
print_eisa_id(id_string, id);
- printk(KERN_ERR "EISA slot %d id mis-match: got %s",
+ printk(KERN_ERR "EISA slot %d id mismatch: got %s",
slot, id_string);
print_eisa_id(id_string, es->eisa_slot_id);
diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
index 1bab5a2cd359..8ba778170447 100644
--- a/drivers/parisc/gsc.c
+++ b/drivers/parisc/gsc.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Interrupt management for most GSC and related devices.
*
@@ -6,11 +7,6 @@
* (c) Copyright 1999 Matthew Wilcox
* (c) Copyright 2000 Helge Deller
* (c) Copyright 2001 Matthew Wilcox for Hewlett-Packard
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
*/
#include <linux/bitops.h>
@@ -139,10 +135,43 @@ static void gsc_asic_unmask_irq(struct irq_data *d)
*/
}
+#ifdef CONFIG_SMP
+static int gsc_set_affinity_irq(struct irq_data *d, const struct cpumask *dest,
+ bool force)
+{
+ struct gsc_asic *gsc_dev = irq_data_get_irq_chip_data(d);
+ struct cpumask tmask;
+ int cpu_irq;
+
+ if (!cpumask_and(&tmask, dest, cpu_online_mask))
+ return -EINVAL;
+
+ cpu_irq = cpu_check_affinity(d, &tmask);
+ if (cpu_irq < 0)
+ return cpu_irq;
+
+ gsc_dev->gsc_irq.txn_addr = txn_affinity_addr(d->irq, cpu_irq);
+ gsc_dev->eim = ((u32) gsc_dev->gsc_irq.txn_addr) | gsc_dev->gsc_irq.txn_data;
+
+ /* switch IRQ's for devices below LASI/WAX to other CPU */
+ /* ASP chip (svers 0x70) does not support reprogramming */
+ if (gsc_dev->gsc->id.sversion != 0x70)
+ gsc_writel(gsc_dev->eim, gsc_dev->hpa + OFFSET_IAR);
+
+ irq_data_update_effective_affinity(d, &tmask);
+
+ return IRQ_SET_MASK_OK;
+}
+#endif
+
+
static struct irq_chip gsc_asic_interrupt_type = {
.name = "GSC-ASIC",
.irq_unmask = gsc_asic_unmask_irq,
.irq_mask = gsc_asic_mask_irq,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = gsc_set_affinity_irq,
+#endif
};
int gsc_assign_irq(struct irq_chip *type, void *data)
@@ -231,18 +260,3 @@ int gsc_common_setup(struct parisc_device *parent, struct gsc_asic *gsc_asic)
return 0;
}
-
-extern struct parisc_driver lasi_driver;
-extern struct parisc_driver asp_driver;
-extern struct parisc_driver wax_driver;
-
-void __init gsc_init(void)
-{
-#ifdef CONFIG_GSC_LASI
- register_parisc_driver(&lasi_driver);
- register_parisc_driver(&asp_driver);
-#endif
-#ifdef CONFIG_GSC_WAX
- register_parisc_driver(&wax_driver);
-#endif
-}
diff --git a/drivers/parisc/gsc.h b/drivers/parisc/gsc.h
index b9d7bfb68e24..73cbd0bb1975 100644
--- a/drivers/parisc/gsc.h
+++ b/drivers/parisc/gsc.h
@@ -1,9 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* drivers/parisc/gsc.h
* Declarations for functions in gsc.c
* Copyright (c) 2000-2002 Helge Deller, Matthew Wilcox
- *
- * Distributed under the terms of the GPL, version 2
*/
#include <linux/interrupt.h>
@@ -32,6 +31,7 @@ struct gsc_asic {
int version;
int type;
int eim;
+ struct gsc_irq gsc_irq;
int global_irq[32];
};
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
index 898208e4f302..0f9d80384e3d 100644
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
** hppb.c:
** HP-PB bus driver for the NOVA and K-Class systems.
@@ -5,10 +6,6 @@
** (c) Copyright 2002 Ryan Bradetich
** (c) Copyright 2002 Hewlett-Packard Company
**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
**
*/
@@ -23,6 +20,8 @@
#include <asm/hardware.h>
#include <asm/parisc-device.h>
+#include "iommu.h"
+
struct hppb_card {
unsigned long hpa;
struct resource mmio_region;
@@ -45,7 +44,7 @@ static struct hppb_card hppb_card_head = {
* (return 1). If so, initialize the chip and tell other partners in crime
* they have work to do.
*/
-static int hppb_probe(struct parisc_device *dev)
+static int __init hppb_probe(struct parisc_device *dev)
{
int status;
struct hppb_card *card = &hppb_card_head;
@@ -62,8 +61,6 @@ static int hppb_probe(struct parisc_device *dev)
}
card = card->next;
}
- printk(KERN_INFO "Found GeckoBoa at 0x%llx\n",
- (unsigned long long) dev->hpa.start);
card->hpa = dev->hpa.start;
card->mmio_region.name = "HP-PB Bus";
@@ -73,15 +70,16 @@ static int hppb_probe(struct parisc_device *dev)
card->mmio_region.end = gsc_readl(dev->hpa.start + IO_IO_HIGH) - 1;
status = ccio_request_resource(dev, &card->mmio_region);
- if(status < 0) {
- printk(KERN_ERR "%s: failed to claim HP-PB bus space (%pR)\n",
- __FILE__, &card->mmio_region);
- }
+
+ pr_info("Found GeckoBoa at %pap, bus space %pR,%s claimed.\n",
+ &dev->hpa.start,
+ &card->mmio_region,
+ (status < 0) ? " not":"" );
return 0;
}
-static struct parisc_device_id hppb_tbl[] = {
+static const struct parisc_device_id hppb_tbl[] __initconst = {
{ HPHW_BCPORT, HVERSION_REV_ANY_ID, 0x500, 0xc }, /* E25 and K */
{ HPHW_BCPORT, 0x0, 0x501, 0xc }, /* E35 */
{ HPHW_BCPORT, 0x0, 0x502, 0xc }, /* E45 */
@@ -89,7 +87,7 @@ static struct parisc_device_id hppb_tbl[] = {
{ 0, }
};
-static struct parisc_driver hppb_driver = {
+static struct parisc_driver hppb_driver __refdata = {
.name = "gecko_boa",
.id_table = hppb_tbl,
.probe = hppb_probe,
@@ -98,9 +96,10 @@ static struct parisc_driver hppb_driver = {
/**
* hppb_init - HP-PB bus initialization procedure.
*
- * Register this driver.
+ * Register this driver.
*/
-void __init hppb_init(void)
+static int __init hppb_init(void)
{
- register_parisc_driver(&hppb_driver);
+ return register_parisc_driver(&hppb_driver);
}
+arch_initcall(hppb_init);
diff --git a/drivers/parisc/iommu-helpers.h b/drivers/parisc/iommu-helpers.h
index 8c33491b21fe..0691884f5095 100644
--- a/drivers/parisc/iommu-helpers.h
+++ b/drivers/parisc/iommu-helpers.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/prefetch.h>
/**
@@ -13,13 +14,13 @@
static inline unsigned int
iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
unsigned long hint,
- void (*iommu_io_pdir_entry)(u64 *, space_t, unsigned long,
+ void (*iommu_io_pdir_entry)(__le64 *, space_t, phys_addr_t,
unsigned long))
{
struct scatterlist *dma_sg = startsg; /* pointer to current DMA */
unsigned int n_mappings = 0;
unsigned long dma_offset = 0, dma_len = 0;
- u64 *pdirp = NULL;
+ __le64 *pdirp = NULL;
/* Horrible hack. For efficiency's sake, dma_sg starts one
* entry below the true start (it is immediately incremented
@@ -27,12 +28,12 @@ iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
dma_sg--;
while (nents-- > 0) {
- unsigned long vaddr;
+ phys_addr_t paddr;
long size;
- DBG_RUN_SG(" %d : %08lx/%05x %08lx/%05x\n", nents,
- (unsigned long)sg_dma_address(startsg), cnt,
- sg_virt_addr(startsg), startsg->length
+ DBG_RUN_SG(" %d : %08lx %p/%05x\n", nents,
+ (unsigned long)sg_dma_address(startsg),
+ sg_virt(startsg), startsg->length
);
@@ -66,7 +67,7 @@ iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
BUG_ON(pdirp == NULL);
- vaddr = sg_virt_addr(startsg);
+ paddr = sg_phys(startsg);
sg_dma_len(dma_sg) += startsg->length;
size = startsg->length + dma_offset;
dma_offset = 0;
@@ -75,8 +76,8 @@ iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents,
#endif
do {
iommu_io_pdir_entry(pdirp, KERNEL_SPACE,
- vaddr, hint);
- vaddr += IOVP_SIZE;
+ paddr, hint);
+ paddr += IOVP_SIZE;
size -= IOVP_SIZE;
pdirp++;
} while(unlikely(size > 0));
@@ -104,7 +105,11 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
struct scatterlist *contig_sg; /* contig chunk head */
unsigned long dma_offset, dma_len; /* start/len of DMA stream */
unsigned int n_mappings = 0;
- unsigned int max_seg_size = dma_get_max_seg_size(dev);
+ unsigned int max_seg_size = min(dma_get_max_seg_size(dev),
+ (unsigned)DMA_CHUNK_SIZE);
+ unsigned int max_seg_boundary = dma_get_seg_boundary(dev) + 1;
+ if (max_seg_boundary) /* check if the addition above didn't overflow */
+ max_seg_size = min(max_seg_size, max_seg_boundary);
while (nents > 0) {
@@ -113,7 +118,7 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
*/
contig_sg = startsg;
dma_len = startsg->length;
- dma_offset = sg_virt_addr(startsg) & ~IOVP_MASK;
+ dma_offset = startsg->offset;
/* PARANOID: clear entries */
sg_dma_address(startsg) = 0;
@@ -124,14 +129,13 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
** it's always looking one "ahead".
*/
while(--nents > 0) {
- unsigned long prevstartsg_end, startsg_end;
+ unsigned long prev_end, sg_start;
- prevstartsg_end = sg_virt_addr(startsg) +
- startsg->length;
+ prev_end = (unsigned long)sg_virt(startsg) +
+ startsg->length;
startsg++;
- startsg_end = sg_virt_addr(startsg) +
- startsg->length;
+ sg_start = (unsigned long)sg_virt(startsg);
/* PARANOID: clear entries */
sg_dma_address(startsg) = 0;
@@ -139,21 +143,21 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
/*
** First make sure current dma stream won't
- ** exceed DMA_CHUNK_SIZE if we coalesce the
+ ** exceed max_seg_size if we coalesce the
** next entry.
*/
- if(unlikely(ALIGN(dma_len + dma_offset + startsg->length,
- IOVP_SIZE) > DMA_CHUNK_SIZE))
- break;
-
- if (startsg->length + dma_len > max_seg_size)
+ if (unlikely(ALIGN(dma_len + dma_offset + startsg->length, IOVP_SIZE) >
+ max_seg_size))
break;
/*
- ** Next see if we can append the next chunk (i.e.
- ** it must end on one page and begin on another
+ * Next see if we can append the next chunk (i.e.
+ * it must end on one page and begin on another, or
+ * it must start on the same address as the previous
+ * entry ended.
*/
- if (unlikely(((prevstartsg_end | sg_virt_addr(startsg)) & ~PAGE_MASK) != 0))
+ if (unlikely((prev_end != sg_start) ||
+ ((prev_end | sg_start) & ~PAGE_MASK)))
break;
dma_len += startsg->length;
diff --git a/drivers/parisc/iommu.h b/drivers/parisc/iommu.h
new file mode 100644
index 000000000000..240059cd8185
--- /dev/null
+++ b/drivers/parisc/iommu.h
@@ -0,0 +1,55 @@
+#ifndef _IOMMU_H
+#define _IOMMU_H 1
+
+#include <linux/pci.h>
+
+struct parisc_device;
+struct ioc;
+
+static inline struct pci_hba_data *parisc_walk_tree(struct device *dev)
+{
+ struct device *otherdev;
+
+ if (likely(dev->platform_data))
+ return dev->platform_data;
+
+ /* OK, just traverse the bus to find it */
+ for (otherdev = dev->parent;
+ otherdev;
+ otherdev = otherdev->parent) {
+ if (otherdev->platform_data) {
+ dev->platform_data = otherdev->platform_data;
+ break;
+ }
+ }
+
+ return dev->platform_data;
+}
+
+static inline struct ioc *GET_IOC(struct device *dev)
+{
+ struct pci_hba_data *pdata = parisc_walk_tree(dev);
+
+ if (!pdata)
+ return NULL;
+ return pdata->iommu;
+}
+
+#ifdef CONFIG_IOMMU_CCIO
+void *ccio_get_iommu(const struct parisc_device *dev);
+int ccio_request_resource(const struct parisc_device *dev,
+ struct resource *res);
+int ccio_allocate_resource(const struct parisc_device *dev,
+ struct resource *res, unsigned long size,
+ unsigned long min, unsigned long max, unsigned long align);
+#else /* !CONFIG_IOMMU_CCIO */
+#define ccio_get_iommu(dev) NULL
+#define ccio_request_resource(dev, res) insert_resource(&iomem_resource, res)
+#define ccio_allocate_resource(dev, res, size, min, max, align) \
+ allocate_resource(&iomem_resource, res, size, min, max, \
+ align, NULL, NULL)
+#endif /* !CONFIG_IOMMU_CCIO */
+
+void *sba_get_iommu(struct parisc_device *dev);
+
+#endif /* _IOMMU_H */
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index e79e006eb9ab..a4011461189b 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
** I/O Sapic Driver - PCI interrupt line support
**
** (c) Copyright 1999 Grant Grundler
** (c) Copyright 1999 Hewlett-Packard Company
**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
**
** The I/O sapic driver manages the Interrupt Redirection Table which is
** the control logic to convert PCI line based interrupts into a Message
@@ -126,21 +123,10 @@
** o disable IRdT - call disable_irq(vector[line]->processor_irq)
*/
-
-/* FIXME: determine which include files are really needed */
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/spinlock.h>
#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <asm/byteorder.h> /* get in-line asm for swab */
#include <asm/pdc.h>
#include <asm/pdcpat.h>
-#include <asm/page.h>
-#include <asm/io.h> /* read/write functions */
#ifdef CONFIG_SUPERIO
#include <asm/superio.h>
#endif
@@ -216,9 +202,9 @@ static inline void iosapic_write(void __iomem *iosapic, unsigned int reg, u32 va
static DEFINE_SPINLOCK(iosapic_lock);
-static inline void iosapic_eoi(void __iomem *addr, unsigned int data)
+static inline void iosapic_eoi(__le32 __iomem *addr, __le32 data)
{
- __raw_writel(data, addr);
+ __raw_writel((__force u32)data, addr);
}
/*
@@ -235,16 +221,7 @@ static size_t irt_num_entry;
static struct irt_entry *iosapic_alloc_irt(int num_entries)
{
- unsigned long a;
-
- /* The IRT needs to be 8-byte aligned for the PDC call.
- * Normally kmalloc would guarantee larger alignment, but
- * if CONFIG_DEBUG_SLAB is enabled, then we can get only
- * 4-byte alignment on 32-bit kernels
- */
- a = (unsigned long)kmalloc(sizeof(struct irt_entry) * num_entries + 8, GFP_KERNEL);
- a = (a + 7UL) & ~7UL;
- return (struct irt_entry *)a;
+ return kcalloc(num_entries, sizeof(struct irt_entry), GFP_KERNEL);
}
/**
@@ -371,13 +348,10 @@ iosapic_load_irt(unsigned long cell_num, struct irt_entry **irt)
}
-
-void __init iosapic_init(void)
+static int __init iosapic_init(void)
{
unsigned long cell = 0;
- DBG("iosapic_init()\n");
-
#ifdef __LP64__
if (is_pdc_pat()) {
int status;
@@ -394,7 +368,10 @@ void __init iosapic_init(void)
irt_num_entry = iosapic_load_irt(cell, &irt_cell);
if (irt_num_entry == 0)
irt_cell = NULL; /* old PDC w/o iosapic */
+
+ return 0;
}
+arch_initcall(iosapic_init);
/*
@@ -691,7 +668,7 @@ static int iosapic_set_affinity_irq(struct irq_data *d,
if (dest_cpu < 0)
return -1;
- cpumask_copy(d->affinity, cpumask_of(dest_cpu));
+ irq_data_update_affinity(d, cpumask_of(dest_cpu));
vi->txn_addr = txn_affinity_addr(d->irq, dest_cpu);
spin_lock_irqsave(&iosapic_lock, flags);
@@ -811,18 +788,28 @@ int iosapic_fixup_irq(void *isi_obj, struct pci_dev *pcidev)
return pcidev->irq;
}
-static struct iosapic_info *first_isi = NULL;
+static struct iosapic_info *iosapic_list;
#ifdef CONFIG_64BIT
-int iosapic_serial_irq(int num)
+int iosapic_serial_irq(struct parisc_device *dev)
{
- struct iosapic_info *isi = first_isi;
- struct irt_entry *irte = NULL; /* only used if PAT PDC */
+ struct iosapic_info *isi;
+ struct irt_entry *irte;
struct vector_info *vi;
- int isi_line; /* line used by device */
+ int cnt;
+ int intin;
+
+ intin = (dev->mod_info >> 24) & 15;
/* lookup IRT entry for isi/slot/pin set */
- irte = &irt_cell[num];
+ for (cnt = 0; cnt < irt_num_entry; cnt++) {
+ irte = &irt_cell[cnt];
+ if (COMPARE_IRTE_ADDR(irte, dev->mod0) &&
+ irte->dest_iosapic_intin == intin)
+ break;
+ }
+ if (cnt >= irt_num_entry)
+ return 0; /* no irq found, force polling */
DBG_IRT("iosapic_serial_irq(): irte %p %x %x %x %x %x %x %x %x\n",
irte,
@@ -834,11 +821,17 @@ int iosapic_serial_irq(int num)
irte->src_seg_id,
irte->dest_iosapic_intin,
(u32) irte->dest_iosapic_addr);
- isi_line = irte->dest_iosapic_intin;
+
+ /* search for iosapic */
+ for (isi = iosapic_list; isi; isi = isi->isi_next)
+ if (isi->isi_hpa == dev->mod0)
+ break;
+ if (!isi)
+ return 0; /* no iosapic found, force polling */
/* get vector info for this input line */
- vi = isi->isi_vector + isi_line;
- DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", isi_line, vi);
+ vi = isi->isi_vector + intin;
+ DBG_IRT("iosapic_serial_irq: line %d vi 0x%p\n", iosapic_intin, vi);
/* If this IRQ line has already been setup, skip it */
if (vi->irte)
@@ -873,6 +866,7 @@ int iosapic_serial_irq(int num)
return vi->txn_irq;
}
+EXPORT_SYMBOL(iosapic_serial_irq);
#endif
@@ -896,7 +890,7 @@ iosapic_rd_version(struct iosapic_info *isi)
** o allocate and initialize isi_vector[]
** o allocate irq region
*/
-void *iosapic_register(unsigned long hpa)
+void *iosapic_register(unsigned long hpa, void __iomem *vaddr)
{
struct iosapic_info *isi = NULL;
struct irt_entry *irte = irt_cell;
@@ -925,7 +919,7 @@ void *iosapic_register(unsigned long hpa)
return NULL;
}
- isi->addr = ioremap_nocache(hpa, 4096);
+ isi->addr = vaddr;
isi->isi_hpa = hpa;
isi->isi_version = iosapic_rd_version(isi);
isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
@@ -941,8 +935,8 @@ void *iosapic_register(unsigned long hpa)
vip->irqline = (unsigned char) cnt;
vip->iosapic = isi;
}
- if (!first_isi)
- first_isi = isi;
+ isi->isi_next = iosapic_list;
+ iosapic_list = isi;
return isi;
}
diff --git a/drivers/parisc/iosapic_private.h b/drivers/parisc/iosapic_private.h
index 6e05e30a2450..bd8ff40162b4 100644
--- a/drivers/parisc/iosapic_private.h
+++ b/drivers/parisc/iosapic_private.h
@@ -1,24 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Private structs/constants for PARISC IOSAPIC support
*
* Copyright (C) 2000 Hewlett Packard (Grant Grundler)
* Copyright (C) 2000,2003 Grant Grundler (grundler at parisc-linux.org)
* Copyright (C) 2002 Matthew Wilcox (willy at parisc-linux.org)
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
@@ -132,8 +118,8 @@ struct iosapic_irt {
struct vector_info {
struct iosapic_info *iosapic; /* I/O SAPIC this vector is on */
struct irt_entry *irte; /* IRT entry */
- u32 __iomem *eoi_addr; /* precalculate EOI reg address */
- u32 eoi_data; /* IA64: ? PA: swapped txn_data */
+ __le32 __iomem *eoi_addr; /* precalculate EOI reg address */
+ __le32 eoi_data; /* IA64: ? PA: swapped txn_data */
int txn_irq; /* virtual IRQ number for processor */
ulong txn_addr; /* IA64: id_eid PA: partial HPA */
u32 txn_data; /* CPU interrupt bit */
diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c
index e65727ca9fc0..73c93e9cfa51 100644
--- a/drivers/parisc/lasi.c
+++ b/drivers/parisc/lasi.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* LASI Device Driver
*
@@ -5,11 +6,6 @@
* Portions (c) Copyright 1999 The Puffin Group Inc.
* Portions (c) Copyright 1999 Hewlett-Packard
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
* by Alan Cox <alan@redhat.com> and
* Alex deVries <alex@onefishtwo.ca>
*/
@@ -21,6 +17,7 @@
#include <linux/module.h>
#include <linux/pm.h>
#include <linux/types.h>
+#include <linux/reboot.h>
#include <asm/io.h>
#include <asm/hardware.h>
@@ -149,25 +146,20 @@ static void __init lasi_led_init(unsigned long lasi_hpa)
* 1 to PWR_ON_L in the Power Control Register
*
*/
-
-static unsigned long lasi_power_off_hpa __read_mostly;
-
-static void lasi_power_off(void)
+static int lasi_power_off(struct sys_off_data *data)
{
- unsigned long datareg;
+ struct gsc_asic *lasi = data->cb_data;
- /* calculate addr of the Power Control Register */
- datareg = lasi_power_off_hpa + 0x0000C000;
+ /* Power down the machine via Power Control Register */
+ gsc_writel(0x02, lasi->hpa + 0x0000C000);
- /* Power down the machine */
- gsc_writel(0x02, datareg);
+ /* might not be reached: */
+ return NOTIFY_DONE;
}
static int __init lasi_init_chip(struct parisc_device *dev)
{
- extern void (*chassis_power_off)(void);
struct gsc_asic *lasi;
- struct gsc_irq gsc_irq;
int ret;
lasi = kzalloc(sizeof(*lasi), GFP_KERNEL);
@@ -189,7 +181,7 @@ static int __init lasi_init_chip(struct parisc_device *dev)
lasi_init_irq(lasi);
/* the IRQ lasi should use */
- dev->irq = gsc_alloc_irq(&gsc_irq);
+ dev->irq = gsc_alloc_irq(&lasi->gsc_irq);
if (dev->irq < 0) {
printk(KERN_ERR "%s(): cannot get GSC irq\n",
__func__);
@@ -197,9 +189,9 @@ static int __init lasi_init_chip(struct parisc_device *dev)
return -EBUSY;
}
- lasi->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+ lasi->eim = ((u32) lasi->gsc_irq.txn_addr) | lasi->gsc_irq.txn_data;
- ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
+ ret = request_irq(lasi->gsc_irq.irq, gsc_asic_intr, 0, "lasi", lasi);
if (ret < 0) {
kfree(lasi);
return ret;
@@ -217,23 +209,27 @@ static int __init lasi_init_chip(struct parisc_device *dev)
gsc_fixup_irqs(dev, lasi, lasi_choose_irq);
- /* initialize the power off function */
- /* FIXME: Record the LASI HPA for the power off function. This should
- * ensure that only the first LASI (the one controlling the power off)
- * should set the HPA here */
- lasi_power_off_hpa = lasi->hpa;
- chassis_power_off = lasi_power_off;
-
+ /* register the LASI power off function */
+ register_sys_off_handler(SYS_OFF_MODE_POWER_OFF,
+ SYS_OFF_PRIO_DEFAULT, lasi_power_off, lasi);
+
return ret;
}
-static struct parisc_device_id lasi_tbl[] = {
+static struct parisc_device_id lasi_tbl[] __initdata = {
{ HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00081 },
{ 0, }
};
+MODULE_DEVICE_TABLE(parisc, lasi_tbl);
-struct parisc_driver lasi_driver = {
+static struct parisc_driver lasi_driver __refdata = {
.name = "lasi",
.id_table = lasi_tbl,
.probe = lasi_init_chip,
};
+
+static int __init lasi_init(void)
+{
+ return register_parisc_driver(&lasi_driver);
+}
+arch_initcall(lasi_init);
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 19f6f70c67d3..3fc3765fddaa 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
**
** PCI Lower Bus Adapter (LBA) manager
@@ -5,10 +6,6 @@
** (c) Copyright 1999,2000 Grant Grundler
** (c) Copyright 1999,2000 Hewlett-Packard Company
**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
**
**
** This module primarily provides access to PCI bus (config/IOport
@@ -49,6 +46,8 @@
#include <asm/parisc-device.h>
#include <asm/io.h> /* read/write stuff */
+#include "iommu.h"
+
#undef DEBUG_LBA /* general stuff */
#undef DEBUG_LBA_PORT /* debug I/O Port access */
#undef DEBUG_LBA_CFG /* debug Config Space Access (ie PCI Bus walk) */
@@ -109,10 +108,10 @@ static u32 lba_t32;
#define LBA_SKIP_PROBE(d) ((d)->flags & LBA_FLAG_SKIP_PROBE)
-
-/* Looks nice and keeps the compiler happy */
-#define LBA_DEV(d) ((struct lba_device *) (d))
-
+static inline struct lba_device *LBA_DEV(struct pci_hba_data *hba)
+{
+ return container_of(hba, struct lba_device, hba);
+}
/*
** Only allow 8 subsidiary busses per LBA
@@ -405,7 +404,7 @@ static int elroy_cfg_read(struct pci_bus *bus, unsigned int devfn, int pos, int
static void
lba_wr_cfg(struct lba_device *d, u32 tok, u8 reg, u32 data, u32 size)
{
- int error = 0;
+ int error __maybe_unused = 0;
u32 arb_mask = 0;
u32 error_config = 0;
u32 status_control = 0;
@@ -624,6 +623,10 @@ extend_lmmio_len(unsigned long start, unsigned long end, unsigned long lba_len)
{
struct resource *tmp;
+ /* exit if not a C8000 */
+ if (boot_cpu_data.cpu_type < mako)
+ return end;
+
pr_debug("LMMIO mismatch: PAT length = 0x%lx, MASK register = 0x%lx\n",
end - start, lba_len);
@@ -631,10 +634,6 @@ extend_lmmio_len(unsigned long start, unsigned long end, unsigned long lba_len)
pr_debug("LBA: lmmio_space [0x%lx-0x%lx] - original\n", start, end);
- if (boot_cpu_data.cpu_type < mako) {
- pr_info("LBA: Not a C8000 system - not extending LMMIO range.\n");
- return end;
- }
end += lba_len;
if (end < start) /* fix overflow */
@@ -665,6 +664,42 @@ extend_lmmio_len(unsigned long start, unsigned long end, unsigned long lba_len)
#define truncate_pat_collision(r,n) (0)
#endif
+static void pcibios_allocate_bridge_resources(struct pci_dev *dev)
+{
+ int idx;
+ struct resource *r;
+
+ for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
+ r = &dev->resource[idx];
+ if (!r->flags)
+ continue;
+ if (r->parent) /* Already allocated */
+ continue;
+ if (!r->start || pci_claim_bridge_resource(dev, idx) < 0) {
+ /*
+ * Something is wrong with the region.
+ * Invalidate the resource to prevent
+ * child resource allocations in this
+ * range.
+ */
+ r->start = r->end = 0;
+ r->flags = 0;
+ }
+ }
+}
+
+static void pcibios_allocate_bus_resources(struct pci_bus *bus)
+{
+ struct pci_bus *child;
+
+ /* Depth-First Search on bus tree */
+ if (bus->self)
+ pcibios_allocate_bridge_resources(bus->self);
+ list_for_each_entry(child, &bus->children, node)
+ pcibios_allocate_bus_resources(child);
+}
+
+
/*
** The algorithm is generic code.
** But it needs to access local data structures to get the IRQ base.
@@ -691,12 +726,11 @@ lba_fixup_bus(struct pci_bus *bus)
** pci_alloc_primary_bus() mangles this.
*/
if (bus->parent) {
- int i;
/* PCI-PCI Bridge */
pci_read_bridge_bases(bus);
- for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
- pci_claim_resource(bus->self, i);
- }
+
+ /* check and allocate bridge resources */
+ pcibios_allocate_bus_resources(bus);
} else {
/* Host-PCI Bridge */
int err;
@@ -791,8 +825,10 @@ lba_fixup_bus(struct pci_bus *bus)
/*
** P2PB's have no IRQs. ignore them.
*/
- if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ pcibios_init_bridge(dev);
continue;
+ }
/* Adjust INTERRUPT_LINE for this dev */
iosapic_fixup_irq(ldev->iosapic_obj, dev);
@@ -982,7 +1018,7 @@ static void
lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
{
unsigned long bytecnt;
- long io_count;
+ long io_count __maybe_unused;
long status; /* PDC return status */
long pa_count;
pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell; /* PA_VIEW */
@@ -1098,7 +1134,7 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
** Postable I/O port space is per PCI host adapter.
** base of 64MB PIOP region
*/
- lba_dev->iop_base = ioremap_nocache(p->start, 64 * 1024 * 1024);
+ lba_dev->iop_base = ioremap(p->start, 64 * 1024 * 1024);
sprintf(lba_dev->hba.io_name, "PCI%02x Ports",
(int)lba_dev->hba.bus_num.start);
@@ -1128,10 +1164,6 @@ lba_pat_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
#endif /* CONFIG_64BIT */
-extern void sba_distributed_lmmio(struct parisc_device *, struct resource *);
-extern void sba_directed_lmmio(struct parisc_device *, struct resource *);
-
-
static void
lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
{
@@ -1236,7 +1268,7 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
r->flags = IORESOURCE_MEM;
/* mmio_mask also clears Enable bit */
r->start &= mmio_mask;
- r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev), r->start);
+ r->start = PCI_HOST_ADDR(&lba_dev->hba, r->start);
rsize = ~ READ_REG32(lba_dev->hba.base_addr + LBA_LMMIO_MASK);
/*
@@ -1282,7 +1314,7 @@ lba_legacy_resources(struct parisc_device *pa_dev, struct lba_device *lba_dev)
r->flags = IORESOURCE_MEM;
/* mmio_mask also clears Enable bit */
r->start &= mmio_mask;
- r->start = PCI_HOST_ADDR(HBA_DATA(lba_dev), r->start);
+ r->start = PCI_HOST_ADDR(&lba_dev->hba, r->start);
rsize = READ_REG32(lba_dev->hba.base_addr + LBA_ELMMIO_MASK);
r->end = r->start + ~rsize;
}
@@ -1364,9 +1396,27 @@ lba_hw_init(struct lba_device *d)
WRITE_REG32(stat, d->hba.base_addr + LBA_ERROR_CONFIG);
}
- /* Set HF mode as the default (vs. -1 mode). */
+
+ /*
+ * Hard Fail vs. Soft Fail on PCI "Master Abort".
+ *
+ * "Master Abort" means the MMIO transaction timed out - usually due to
+ * the device not responding to an MMIO read. We would like HF to be
+ * enabled to find driver problems, though it means the system will
+ * crash with a HPMC.
+ *
+ * In SoftFail mode "~0L" is returned as a result of a timeout on the
+ * pci bus. This is like how PCI busses on x86 and most other
+ * architectures behave. In order to increase compatibility with
+ * existing (x86) PCI hardware and existing Linux drivers we enable
+ * Soft Faul mode on PA-RISC now too.
+ */
stat = READ_REG32(d->hba.base_addr + LBA_STAT_CTL);
+#if defined(ENABLE_HARDFAIL)
WRITE_REG32(stat | HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL);
+#else
+ WRITE_REG32(stat & ~HF_ENABLE, d->hba.base_addr + LBA_STAT_CTL);
+#endif
/*
** Writing a zero to STAT_CTL.rf (bit 0) will clear reset signal
@@ -1422,9 +1472,13 @@ lba_driver_probe(struct parisc_device *dev)
u32 func_class;
void *tmp_obj;
char *version;
- void __iomem *addr = ioremap_nocache(dev->hpa.start, 4096);
+ void __iomem *addr;
int max;
+ addr = ioremap(dev->hpa.start, 4096);
+ if (addr == NULL)
+ return -ENOMEM;
+
/* Read HW Rev First */
func_class = READ_REG32(addr + LBA_FCLASS);
@@ -1481,7 +1535,8 @@ lba_driver_probe(struct parisc_device *dev)
}
/* Tell I/O SAPIC driver we have a IRQ handler/region. */
- tmp_obj = iosapic_register(dev->hpa.start + LBA_IOSAPIC_BASE);
+ tmp_obj = iosapic_register(dev->hpa.start + LBA_IOSAPIC_BASE,
+ addr + LBA_IOSAPIC_BASE);
/* NOTE: PCI devices (e.g. 103c:1005 graphics card) which don't
** have an IRT entry will get NULL back from iosapic code.
@@ -1505,7 +1560,7 @@ lba_driver_probe(struct parisc_device *dev)
/* ------------ Second : initialize common stuff ---------- */
pci_bios = &lba_bios_ops;
- pcibios_register_hba(HBA_DATA(lba_dev));
+ pcibios_register_hba(&lba_dev->hba);
spin_lock_init(&lba_dev->lba_lock);
if (lba_hw_init(lba_dev))
@@ -1521,7 +1576,7 @@ lba_driver_probe(struct parisc_device *dev)
} else {
if (!astro_iop_base) {
/* Sprockets PDC uses NPIOP region */
- astro_iop_base = ioremap_nocache(LBA_PORT_BASE, 64 * 1024);
+ astro_iop_base = ioremap(LBA_PORT_BASE, 64 * 1024);
pci_port = &lba_astro_port_ops;
}
@@ -1557,8 +1612,11 @@ lba_driver_probe(struct parisc_device *dev)
if (lba_dev->hba.lmmio_space.flags)
pci_add_resource_offset(&resources, &lba_dev->hba.lmmio_space,
lba_dev->hba.lmmio_space_offset);
- if (lba_dev->hba.gmmio_space.flags)
- pci_add_resource(&resources, &lba_dev->hba.gmmio_space);
+ if (lba_dev->hba.gmmio_space.flags) {
+ /* Not registering GMMIO space - according to docs it's not
+ * even used on HP-UX. */
+ /* pci_add_resource(&resources, &lba_dev->hba.gmmio_space); */
+ }
pci_add_resource(&resources, &lba_dev->hba.bus_num);
@@ -1590,7 +1648,6 @@ lba_driver_probe(struct parisc_device *dev)
lba_dump_res(&lba_dev->hba.lmmio_space, 2);
#endif
}
- pci_enable_bridges(lba_bus);
/*
** Once PCI register ops has walked the bus, access to config
@@ -1608,14 +1665,14 @@ lba_driver_probe(struct parisc_device *dev)
return 0;
}
-static struct parisc_device_id lba_tbl[] = {
+static const struct parisc_device_id lba_tbl[] __initconst = {
{ HPHW_BRIDGE, HVERSION_REV_ANY_ID, ELROY_HVERS, 0xa },
{ HPHW_BRIDGE, HVERSION_REV_ANY_ID, MERCURY_HVERS, 0xa },
{ HPHW_BRIDGE, HVERSION_REV_ANY_ID, QUICKSILVER_HVERS, 0xa },
{ 0, }
};
-static struct parisc_driver lba_driver = {
+static struct parisc_driver lba_driver __refdata = {
.name = MODULE_NAME,
.id_table = lba_tbl,
.probe = lba_driver_probe,
@@ -1625,10 +1682,11 @@ static struct parisc_driver lba_driver = {
** One time initialization to let the world know the LBA was found.
** Must be called exactly once before pci_init().
*/
-void __init lba_init(void)
+static int __init lba_init(void)
{
- register_parisc_driver(&lba_driver);
+ return register_parisc_driver(&lba_driver);
}
+arch_initcall(lba_init);
/*
** Initialize the IBASE/IMASK registers for LBA (Elroy).
@@ -1637,7 +1695,7 @@ void __init lba_init(void)
*/
void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask)
{
- void __iomem * base_addr = ioremap_nocache(lba->hpa.start, 4096);
+ void __iomem * base_addr = ioremap(lba->hpa.start, 4096);
imask <<= 2; /* adjust for hints - 2 more bits */
@@ -1651,3 +1709,48 @@ void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask)
iounmap(base_addr);
}
+
+/*
+ * The design of the Diva management card in rp34x0 machines (rp3410, rp3440)
+ * seems rushed, so that many built-in components simply don't work.
+ * The following quirks disable the serial AUX port and the built-in ATI RV100
+ * Radeon 7000 graphics card which both don't have any external connectors and
+ * thus are useless, and even worse, e.g. the AUX port occupies ttyS0 and as
+ * such makes those machines the only PARISC machines on which we can't use
+ * ttyS0 as boot console.
+ */
+static void quirk_diva_ati_card(struct pci_dev *dev)
+{
+ if (dev->subsystem_vendor != PCI_VENDOR_ID_HP ||
+ dev->subsystem_device != 0x1292)
+ return;
+
+ dev_info(&dev->dev, "Hiding Diva built-in ATI card");
+ dev->device = 0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_QY,
+ quirk_diva_ati_card);
+
+static void quirk_diva_aux_disable(struct pci_dev *dev)
+{
+ if (dev->subsystem_vendor != PCI_VENDOR_ID_HP ||
+ dev->subsystem_device != 0x1291)
+ return;
+
+ dev_info(&dev->dev, "Hiding Diva built-in AUX serial device");
+ dev->device = 0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA_AUX,
+ quirk_diva_aux_disable);
+
+static void quirk_tosca_aux_disable(struct pci_dev *dev)
+{
+ if (dev->subsystem_vendor != PCI_VENDOR_ID_HP ||
+ dev->subsystem_device != 0x104a)
+ return;
+
+ dev_info(&dev->dev, "Hiding Tosca secondary built-in AUX serial device");
+ dev->device = 0;
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_DIVA,
+ quirk_tosca_aux_disable);
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index b48243131993..016c9d5a60a8 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -1,81 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * Chassis LCD/LED driver for HP-PARISC workstations
+ * Chassis LCD/LED driver for HP-PARISC workstations
*
- * (c) Copyright 2000 Red Hat Software
- * (c) Copyright 2000 Helge Deller <hdeller@redhat.com>
- * (c) Copyright 2001-2009 Helge Deller <deller@gmx.de>
- * (c) Copyright 2001 Randolph Chung <tausq@debian.org>
+ * (c) Copyright 2000 Red Hat Software
+ * (c) Copyright 2000 Helge Deller <hdeller@redhat.com>
+ * (c) Copyright 2001 Randolph Chung <tausq@debian.org>
+ * (c) Copyright 2000-2023 Helge Deller <deller@gmx.de>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * The control of the LEDs and LCDs on PARISC machines has to be done
+ * completely in software.
*
- * TODO:
- * - speed-up calculations with inlined assembler
- * - interface to write to second row of LCD from /proc (if technically possible)
- *
- * Changes:
- * - Audit copy_from_user in led_proc_write.
- * Daniele Bellucci <bellucda@tiscali.it>
- * - Switch from using a tasklet to a work queue, so the led_LCD_driver
- * can sleep.
- * David Pye <dmp@davidmpye.dyndns.org>
+ * The LEDs can be configured at runtime in /sys/class/leds/
*/
#include <linux/module.h>
-#include <linux/stddef.h> /* for offsetof() */
#include <linux/init.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/utsname.h>
#include <linux/capability.h>
#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/in.h>
-#include <linux/interrupt.h>
-#include <linux/kernel_stat.h>
#include <linux/reboot.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/ctype.h>
-#include <linux/blkdev.h>
-#include <linux/workqueue.h>
-#include <linux/rcupdate.h>
+#include <linux/uaccess.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+
#include <asm/io.h>
#include <asm/processor.h>
#include <asm/hardware.h>
#include <asm/param.h> /* HZ */
#include <asm/led.h>
#include <asm/pdc.h>
-#include <asm/uaccess.h>
-
-/* The control of the LEDs and LCDs on PARISC-machines have to be done
- completely in software. The necessary calculations are done in a work queue
- task which is scheduled regularly, and since the calculations may consume a
- relatively large amount of CPU time, some of the calculations can be
- turned off with the following variables (controlled via procfs) */
-
-static int led_type __read_mostly = -1;
-static unsigned char lastleds; /* LED state from most recent update */
-static unsigned int led_heartbeat __read_mostly = 1;
-static unsigned int led_diskio __read_mostly = 1;
-static unsigned int led_lanrxtx __read_mostly = 1;
-static char lcd_text[32] __read_mostly;
-static char lcd_text_default[32] __read_mostly;
-static int lcd_no_led_support __read_mostly = 0; /* KittyHawk doesn't support LED on its LCD */
-
-
-static struct workqueue_struct *led_wq;
-static void led_work_func(struct work_struct *);
-static DECLARE_DELAYED_WORK(led_task, led_work_func);
-
-#if 0
-#define DPRINTK(x) printk x
-#else
-#define DPRINTK(x)
-#endif
+
+#define LED_HAS_LCD 1
+#define LED_HAS_LED 2
+
+static unsigned char led_type; /* bitmask of LED_HAS_XXX */
+static unsigned char lastleds; /* LED state from most recent update */
+static unsigned char lcd_new_text;
+static unsigned char lcd_text[20];
+static unsigned char lcd_no_led_support; /* KittyHawk doesn't support LED on its LCD */
struct lcd_block {
unsigned char command; /* stores the command byte */
@@ -84,7 +48,7 @@ struct lcd_block {
};
/* Structure returned by PDC_RETURN_CHASSIS_INFO */
-/* NOTE: we use unsigned long:16 two times, since the following member
+/* NOTE: we use unsigned long:16 two times, since the following member
lcd_cmd_reg_addr needs to be 64bit aligned on 64bit PA2.0-machines */
struct pdc_chassis_lcd_info_ret_block {
unsigned long model:16; /* DISPLAY_MODEL_XXXX */
@@ -104,15 +68,15 @@ struct pdc_chassis_lcd_info_ret_block {
/* LCD_CMD and LCD_DATA for KittyHawk machines */
-#define KITTYHAWK_LCD_CMD F_EXTEND(0xf0190000UL) /* 64bit-ready */
-#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD+1)
+#define KITTYHAWK_LCD_CMD F_EXTEND(0xf0190000UL)
+#define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD + 1)
-/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's
+/* lcd_info is pre-initialized to the values needed to program KittyHawk LCD's
* HP seems to have used Sharp/Hitachi HD44780 LCDs most of the time. */
static struct pdc_chassis_lcd_info_ret_block
-lcd_info __attribute__((aligned(8))) __read_mostly =
+lcd_info __attribute__((aligned(8))) =
{
- .model = DISPLAY_MODEL_LCD,
+ .model = DISPLAY_MODEL_NONE,
.lcd_width = 16,
.lcd_cmd_reg_addr = KITTYHAWK_LCD_CMD,
.lcd_data_reg_addr = KITTYHAWK_LCD_DATA,
@@ -121,163 +85,65 @@ lcd_info __attribute__((aligned(8))) __read_mostly =
.reset_cmd2 = 0xc0,
};
-
/* direct access to some of the lcd_info variables */
-#define LCD_CMD_REG lcd_info.lcd_cmd_reg_addr
-#define LCD_DATA_REG lcd_info.lcd_data_reg_addr
+#define LCD_CMD_REG lcd_info.lcd_cmd_reg_addr
+#define LCD_DATA_REG lcd_info.lcd_data_reg_addr
#define LED_DATA_REG lcd_info.lcd_cmd_reg_addr /* LASI & ASP only */
-#define LED_HASLCD 1
-#define LED_NOLCD 0
-
-/* The workqueue must be created at init-time */
-static int start_task(void)
-{
- /* Display the default text now */
- if (led_type == LED_HASLCD) lcd_print( lcd_text_default );
-
- /* KittyHawk has no LED support on its LCD */
- if (lcd_no_led_support) return 0;
-
- /* Create the work queue and queue the LED task */
- led_wq = create_singlethread_workqueue("led_wq");
- queue_delayed_work(led_wq, &led_task, 0);
-
- return 0;
-}
-
-device_initcall(start_task);
-
/* ptr to LCD/LED-specific function */
-static void (*led_func_ptr) (unsigned char) __read_mostly;
-
-#ifdef CONFIG_PROC_FS
-static int led_proc_show(struct seq_file *m, void *v)
-{
- switch ((long)m->private)
- {
- case LED_NOLCD:
- seq_printf(m, "Heartbeat: %d\n", led_heartbeat);
- seq_printf(m, "Disk IO: %d\n", led_diskio);
- seq_printf(m, "LAN Rx/Tx: %d\n", led_lanrxtx);
- break;
- case LED_HASLCD:
- seq_printf(m, "%s\n", lcd_text);
- break;
- default:
- return 0;
- }
- return 0;
-}
-
-static int led_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, led_proc_show, PDE_DATA(inode));
-}
+static void (*led_func_ptr) (unsigned char);
-static ssize_t led_proc_write(struct file *file, const char *buf,
- size_t count, loff_t *pos)
+static void lcd_print_now(void)
{
- void *data = PDE_DATA(file_inode(file));
- char *cur, lbuf[32];
- int d;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
- if (count >= sizeof(lbuf))
- count = sizeof(lbuf)-1;
-
- if (copy_from_user(lbuf, buf, count))
- return -EFAULT;
- lbuf[count] = 0;
-
- cur = lbuf;
-
- switch ((long)data)
- {
- case LED_NOLCD:
- d = *cur++ - '0';
- if (d != 0 && d != 1) goto parse_error;
- led_heartbeat = d;
-
- if (*cur++ != ' ') goto parse_error;
+ int i;
+ char *str = lcd_text;
- d = *cur++ - '0';
- if (d != 0 && d != 1) goto parse_error;
- led_diskio = d;
+ if (lcd_info.model != DISPLAY_MODEL_LCD)
+ return;
- if (*cur++ != ' ') goto parse_error;
+ if (!lcd_new_text)
+ return;
+ lcd_new_text = 0;
- d = *cur++ - '0';
- if (d != 0 && d != 1) goto parse_error;
- led_lanrxtx = d;
+ /* Set LCD Cursor to 1st character */
+ gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG);
+ udelay(lcd_info.min_cmd_delay);
- break;
- case LED_HASLCD:
- if (*cur && cur[strlen(cur)-1] == '\n')
- cur[strlen(cur)-1] = 0;
- if (*cur == 0)
- cur = lcd_text_default;
- lcd_print(cur);
- break;
- default:
- return 0;
+ /* Print the string */
+ for (i = 0; i < lcd_info.lcd_width; i++) {
+ gsc_writeb(*str ? *str++ : ' ', LCD_DATA_REG);
+ udelay(lcd_info.min_cmd_delay);
}
-
- return count;
-
-parse_error:
- if ((long)data == LED_NOLCD)
- printk(KERN_CRIT "Parse error: expect \"n n n\" (n == 0 or 1) for heartbeat,\ndisk io and lan tx/rx indicators\n");
- return -EINVAL;
}
-static const struct file_operations led_proc_fops = {
- .owner = THIS_MODULE,
- .open = led_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = led_proc_write,
-};
-
-static int __init led_create_procfs(void)
+/**
+ * lcd_print()
+ *
+ * @str: string to show on the LCD. If NULL, print current string again.
+ *
+ * Displays the given string on the LCD-Display of newer machines.
+ */
+void lcd_print(const char *str)
{
- struct proc_dir_entry *proc_pdc_root = NULL;
- struct proc_dir_entry *ent;
-
- if (led_type == -1) return -1;
-
- proc_pdc_root = proc_mkdir("pdc", 0);
- if (!proc_pdc_root) return -1;
-
- if (!lcd_no_led_support)
- {
- ent = proc_create_data("led", S_IRUGO|S_IWUSR, proc_pdc_root,
- &led_proc_fops, (void *)LED_NOLCD); /* LED */
- if (!ent) return -1;
- }
-
- if (led_type == LED_HASLCD)
- {
- ent = proc_create_data("lcd", S_IRUGO|S_IWUSR, proc_pdc_root,
- &led_proc_fops, (void *)LED_HASLCD); /* LCD */
- if (!ent) return -1;
- }
+ /* copy display string to buffer for procfs */
+ if (str)
+ strscpy(lcd_text, str, sizeof(lcd_text));
+ lcd_new_text = 1;
- return 0;
+ /* print now if LCD without any LEDs */
+ if (led_type == LED_HAS_LCD)
+ lcd_print_now();
}
-#endif
-/*
- **
- ** led_ASP_driver()
- **
- */
#define LED_DATA 0x01 /* data to shift (0:on 1:off) */
#define LED_STROBE 0x02 /* strobe to clock data */
+
+/**
+ * led_ASP_driver() - LED driver for the ASP controller chip
+ *
+ * @leds: bitmap representing the LED status
+ */
static void led_ASP_driver(unsigned char leds)
{
int i;
@@ -292,11 +158,10 @@ static void led_ASP_driver(unsigned char leds)
}
}
-
-/*
- **
- ** led_LASI_driver()
- **
+/**
+ * led_LASI_driver() - LED driver for the LASI controller chip
+ *
+ * @leds: bitmap representing the LED status
*/
static void led_LASI_driver(unsigned char leds)
{
@@ -304,392 +169,295 @@ static void led_LASI_driver(unsigned char leds)
gsc_writeb( leds, LED_DATA_REG );
}
-
-/*
- **
- ** led_LCD_driver()
- **
+/**
+ * led_LCD_driver() - LED & LCD driver for LCD chips
+ *
+ * @leds: bitmap representing the LED status
*/
static void led_LCD_driver(unsigned char leds)
{
- static int i;
- static unsigned char mask[4] = { LED_HEARTBEAT, LED_DISK_IO,
+ static const unsigned char mask[4] = {
+ LED_HEARTBEAT, LED_DISK_IO,
LED_LAN_RCV, LED_LAN_TX };
-
- static struct lcd_block * blockp[4] = {
+
+ static struct lcd_block * const blockp[4] = {
&lcd_info.heartbeat,
&lcd_info.disk_io,
&lcd_info.lan_rcv,
&lcd_info.lan_tx
};
+ static unsigned char latest_leds;
+ int i;
- /* Convert min_cmd_delay to milliseconds */
- unsigned int msec_cmd_delay = 1 + (lcd_info.min_cmd_delay / 1000);
-
- for (i=0; i<4; ++i)
- {
- if ((leds & mask[i]) != (lastleds & mask[i]))
- {
- gsc_writeb( blockp[i]->command, LCD_CMD_REG );
- msleep(msec_cmd_delay);
-
- gsc_writeb( leds & mask[i] ? blockp[i]->on :
- blockp[i]->off, LCD_DATA_REG );
- msleep(msec_cmd_delay);
- }
- }
-}
+ for (i = 0; i < 4; ++i) {
+ if ((leds & mask[i]) == (latest_leds & mask[i]))
+ continue;
+ gsc_writeb( blockp[i]->command, LCD_CMD_REG );
+ udelay(lcd_info.min_cmd_delay);
-/*
- **
- ** led_get_net_activity()
- **
- ** calculate if there was TX- or RX-throughput on the network interfaces
- ** (analog to dev_get_info() from net/core/dev.c)
- **
- */
-static __inline__ int led_get_net_activity(void)
-{
-#ifndef CONFIG_NET
- return 0;
-#else
- static u64 rx_total_last, tx_total_last;
- u64 rx_total, tx_total;
- struct net_device *dev;
- int retval;
-
- rx_total = tx_total = 0;
-
- /* we are running as a workqueue task, so we can use an RCU lookup */
- rcu_read_lock();
- for_each_netdev_rcu(&init_net, dev) {
- const struct rtnl_link_stats64 *stats;
- struct rtnl_link_stats64 temp;
- struct in_device *in_dev = __in_dev_get_rcu(dev);
- if (!in_dev || !in_dev->ifa_list)
- continue;
- if (ipv4_is_loopback(in_dev->ifa_list->ifa_local))
- continue;
- stats = dev_get_stats(dev, &temp);
- rx_total += stats->rx_packets;
- tx_total += stats->tx_packets;
+ gsc_writeb( leds & mask[i] ? blockp[i]->on :
+ blockp[i]->off, LCD_DATA_REG );
+ udelay(lcd_info.min_cmd_delay);
}
- rcu_read_unlock();
+ latest_leds = leds;
- retval = 0;
+ lcd_print_now();
+}
- if (rx_total != rx_total_last) {
- rx_total_last = rx_total;
- retval |= LED_LAN_RCV;
- }
- if (tx_total != tx_total_last) {
- tx_total_last = tx_total;
- retval |= LED_LAN_TX;
- }
+/**
+ * lcd_system_halt()
+ *
+ * @nb: pointer to the notifier_block structure
+ * @event: the event (SYS_RESTART, SYS_HALT or SYS_POWER_OFF)
+ * @buf: pointer to a buffer (not used)
+ *
+ * Called by the reboot notifier chain at shutdown. Stops all
+ * LED/LCD activities.
+ */
+static int lcd_system_halt(struct notifier_block *nb, unsigned long event, void *buf)
+{
+ const char *txt;
- return retval;
-#endif
-}
+ switch (event) {
+ case SYS_RESTART: txt = "SYSTEM RESTART";
+ break;
+ case SYS_HALT: txt = "SYSTEM HALT";
+ break;
+ case SYS_POWER_OFF: txt = "SYSTEM POWER OFF";
+ break;
+ default: return NOTIFY_DONE;
+ }
+ lcd_print(txt);
-/*
- **
- ** led_get_diskio_activity()
- **
- ** calculate if there was disk-io in the system
- **
- */
-static __inline__ int led_get_diskio_activity(void)
-{
- static unsigned long last_pgpgin, last_pgpgout;
- unsigned long events[NR_VM_EVENT_ITEMS];
- int changed;
-
- all_vm_events(events);
-
- /* Just use a very simple calculation here. Do not care about overflow,
- since we only want to know if there was activity or not. */
- changed = (events[PGPGIN] != last_pgpgin) ||
- (events[PGPGOUT] != last_pgpgout);
- last_pgpgin = events[PGPGIN];
- last_pgpgout = events[PGPGOUT];
-
- return (changed ? LED_DISK_IO : 0);
+ return NOTIFY_OK;
}
+static struct notifier_block lcd_system_halt_notifier = {
+ .notifier_call = lcd_system_halt,
+};
+static void set_led(struct led_classdev *led_cdev, enum led_brightness brightness);
-/*
- ** led_work_func()
- **
- ** manages when and which chassis LCD/LED gets updated
-
- TODO:
- - display load average (older machines like 715/64 have 4 "free" LED's for that)
- - optimizations
- */
+struct hppa_led {
+ struct led_classdev led_cdev;
+ unsigned char led_bit;
+};
+#define to_hppa_led(d) container_of(d, struct hppa_led, led_cdev)
-#define HEARTBEAT_LEN (HZ*10/100)
-#define HEARTBEAT_2ND_RANGE_START (HZ*28/100)
-#define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN)
+typedef void (*set_handler)(struct led_classdev *, enum led_brightness);
+struct led_type {
+ const char *name;
+ set_handler handler;
+ const char *default_trigger;
+};
-#define LED_UPDATE_INTERVAL (1 + (HZ*19/1000))
+#define NUM_LEDS_PER_BOARD 8
+struct hppa_drvdata {
+ struct hppa_led leds[NUM_LEDS_PER_BOARD];
+};
-static void led_work_func (struct work_struct *unused)
+static void set_led(struct led_classdev *led_cdev, enum led_brightness brightness)
{
- static unsigned long last_jiffies;
- static unsigned long count_HZ; /* counter in range 0..HZ */
- unsigned char currentleds = 0; /* stores current value of the LEDs */
+ struct hppa_led *p = to_hppa_led(led_cdev);
+ unsigned char led_bit = p->led_bit;
- /* exit if not initialized */
- if (!led_func_ptr)
- return;
+ if (brightness == LED_OFF)
+ lastleds &= ~led_bit;
+ else
+ lastleds |= led_bit;
- /* increment the heartbeat timekeeper */
- count_HZ += jiffies - last_jiffies;
- last_jiffies = jiffies;
- if (count_HZ >= HZ)
- count_HZ = 0;
+ if (led_func_ptr)
+ led_func_ptr(lastleds);
+}
- if (likely(led_heartbeat))
- {
- /* flash heartbeat-LED like a real heart
- * (2 x short then a long delay)
- */
- if (count_HZ < HEARTBEAT_LEN ||
- (count_HZ >= HEARTBEAT_2ND_RANGE_START &&
- count_HZ < HEARTBEAT_2ND_RANGE_END))
- currentleds |= LED_HEARTBEAT;
- }
- if (likely(led_lanrxtx)) currentleds |= led_get_net_activity();
- if (likely(led_diskio)) currentleds |= led_get_diskio_activity();
-
- /* blink LEDs if we got an Oops (HPMC) */
- if (unlikely(oops_in_progress)) {
- if (boot_cpu_data.cpu_type >= pcxl2) {
- /* newer machines don't have loadavg. LEDs, so we
- * let all LEDs blink twice per second instead */
- currentleds = (count_HZ <= (HZ/2)) ? 0 : 0xff;
- } else {
- /* old machines: blink loadavg. LEDs twice per second */
- if (count_HZ <= (HZ/2))
- currentleds &= ~(LED4|LED5|LED6|LED7);
- else
- currentleds |= (LED4|LED5|LED6|LED7);
+static int hppa_led_generic_probe(struct platform_device *pdev,
+ struct led_type *types)
+{
+ struct hppa_drvdata *p;
+ int i, err;
+
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ for (i = 0; i < NUM_LEDS_PER_BOARD; i++) {
+ struct led_classdev *lp = &p->leds[i].led_cdev;
+
+ p->leds[i].led_bit = BIT(i);
+ lp->name = types[i].name;
+ lp->brightness = LED_FULL;
+ lp->brightness_set = types[i].handler;
+ lp->default_trigger = types[i].default_trigger;
+ err = led_classdev_register(&pdev->dev, lp);
+ if (err) {
+ dev_err(&pdev->dev, "Could not register %s LED\n",
+ lp->name);
+ for (i--; i >= 0; i--)
+ led_classdev_unregister(&p->leds[i].led_cdev);
+ return err;
}
}
- if (currentleds != lastleds)
- {
- led_func_ptr(currentleds); /* Update the LCD/LEDs */
- lastleds = currentleds;
- }
+ platform_set_drvdata(pdev, p);
- queue_delayed_work(led_wq, &led_task, LED_UPDATE_INTERVAL);
+ return 0;
}
-/*
- ** led_halt()
- **
- ** called by the reboot notifier chain at shutdown and stops all
- ** LED/LCD activities.
- **
- */
+static void platform_led_remove(struct platform_device *pdev)
+{
+ struct hppa_drvdata *p = platform_get_drvdata(pdev);
+ int i;
-static int led_halt(struct notifier_block *, unsigned long, void *);
+ for (i = 0; i < NUM_LEDS_PER_BOARD; i++)
+ led_classdev_unregister(&p->leds[i].led_cdev);
+}
-static struct notifier_block led_notifier = {
- .notifier_call = led_halt,
+static struct led_type mainboard_led_types[NUM_LEDS_PER_BOARD] = {
+ {
+ .name = "platform-lan-tx",
+ .handler = set_led,
+ .default_trigger = "tx",
+ },
+ {
+ .name = "platform-lan-rx",
+ .handler = set_led,
+ .default_trigger = "rx",
+ },
+ {
+ .name = "platform-disk",
+ .handler = set_led,
+ .default_trigger = "disk-activity",
+ },
+ {
+ .name = "platform-heartbeat",
+ .handler = set_led,
+ .default_trigger = "heartbeat",
+ },
+ {
+ .name = "platform-LED4",
+ .handler = set_led,
+ .default_trigger = "panic",
+ },
+ {
+ .name = "platform-LED5",
+ .handler = set_led,
+ .default_trigger = "panic",
+ },
+ {
+ .name = "platform-LED6",
+ .handler = set_led,
+ .default_trigger = "panic",
+ },
+ {
+ .name = "platform-LED7",
+ .handler = set_led,
+ .default_trigger = "panic",
+ },
};
-static int notifier_disabled = 0;
-static int led_halt(struct notifier_block *nb, unsigned long event, void *buf)
+static int platform_led_probe(struct platform_device *pdev)
{
- char *txt;
+ return hppa_led_generic_probe(pdev, mainboard_led_types);
+}
- if (notifier_disabled)
- return NOTIFY_OK;
+MODULE_ALIAS("platform:platform-leds");
- notifier_disabled = 1;
- switch (event) {
- case SYS_RESTART: txt = "SYSTEM RESTART";
- break;
- case SYS_HALT: txt = "SYSTEM HALT";
- break;
- case SYS_POWER_OFF: txt = "SYSTEM POWER OFF";
- break;
- default: return NOTIFY_DONE;
- }
-
- /* Cancel the work item and delete the queue */
- if (led_wq) {
- cancel_delayed_work_sync(&led_task);
- destroy_workqueue(led_wq);
- led_wq = NULL;
- }
-
- if (lcd_info.model == DISPLAY_MODEL_LCD)
- lcd_print(txt);
- else
- if (led_func_ptr)
- led_func_ptr(0xff); /* turn all LEDs ON */
-
- return NOTIFY_OK;
-}
+static struct platform_driver hppa_mainboard_led_driver = {
+ .probe = platform_led_probe,
+ .remove = platform_led_remove,
+ .driver = {
+ .name = "platform-leds",
+ },
+};
-/*
- ** register_led_driver()
- **
- ** registers an external LED or LCD for usage by this driver.
- ** currently only LCD-, LASI- and ASP-style LCD/LED's are supported.
- **
- */
+static struct platform_driver * const drivers[] = {
+ &hppa_mainboard_led_driver,
+};
+static struct platform_device platform_leds = {
+ .name = "platform-leds",
+};
+
+/**
+ * register_led_driver()
+ *
+ * @model: model type, one of the DISPLAY_MODEL_XXXX values
+ * @cmd_reg: physical address of cmd register for the LED/LCD
+ * @data_reg: physical address of data register for the LED/LCD
+ *
+ * Registers a chassis LED or LCD which should be driven by this driver.
+ * Only PDC-based, LASI- or ASP-style LEDs and LCDs are supported.
+ */
int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long data_reg)
{
- static int initialized;
-
- if (initialized || !data_reg)
+ if (led_func_ptr || !data_reg)
+ return 1;
+
+ /* No LEDs when running in QEMU */
+ if (running_on_qemu)
return 1;
-
+
lcd_info.model = model; /* store the values */
LCD_CMD_REG = (cmd_reg == LED_CMD_REG_NONE) ? 0 : cmd_reg;
switch (lcd_info.model) {
case DISPLAY_MODEL_LCD:
LCD_DATA_REG = data_reg;
- printk(KERN_INFO "LCD display at %lx,%lx registered\n",
+ pr_info("led: LCD display at %#lx and %#lx\n",
LCD_CMD_REG , LCD_DATA_REG);
led_func_ptr = led_LCD_driver;
- led_type = LED_HASLCD;
+ if (lcd_no_led_support)
+ led_type = LED_HAS_LCD;
+ else
+ led_type = LED_HAS_LCD | LED_HAS_LED;
break;
case DISPLAY_MODEL_LASI:
LED_DATA_REG = data_reg;
led_func_ptr = led_LASI_driver;
- printk(KERN_INFO "LED display at %lx registered\n", LED_DATA_REG);
- led_type = LED_NOLCD;
+ pr_info("led: LED display at %#lx\n", LED_DATA_REG);
+ led_type = LED_HAS_LED;
break;
case DISPLAY_MODEL_OLD_ASP:
LED_DATA_REG = data_reg;
led_func_ptr = led_ASP_driver;
- printk(KERN_INFO "LED (ASP-style) display at %lx registered\n",
+ pr_info("led: LED (ASP-style) display at %#lx\n",
LED_DATA_REG);
- led_type = LED_NOLCD;
+ led_type = LED_HAS_LED;
break;
default:
- printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n",
- __func__, lcd_info.model);
+ pr_err("led: Unknown LCD/LED model type %d\n", lcd_info.model);
return 1;
}
-
- /* mark the LCD/LED driver now as initialized and
- * register to the reboot notifier chain */
- initialized++;
- register_reboot_notifier(&led_notifier);
-
- /* Ensure the work is queued */
- if (led_wq) {
- queue_delayed_work(led_wq, &led_task, 0);
- }
- return 0;
-}
-
-/*
- ** register_led_regions()
- **
- ** register_led_regions() registers the LCD/LED regions for /procfs.
- ** At bootup - where the initialisation of the LCD/LED normally happens -
- ** not all internal structures of request_region() are properly set up,
- ** so that we delay the led-registration until after busdevices_init()
- ** has been executed.
- **
- */
+ platform_register_drivers(drivers, ARRAY_SIZE(drivers));
-void __init register_led_regions(void)
-{
- switch (lcd_info.model) {
- case DISPLAY_MODEL_LCD:
- request_mem_region((unsigned long)LCD_CMD_REG, 1, "lcd_cmd");
- request_mem_region((unsigned long)LCD_DATA_REG, 1, "lcd_data");
- break;
- case DISPLAY_MODEL_LASI:
- case DISPLAY_MODEL_OLD_ASP:
- request_mem_region((unsigned long)LED_DATA_REG, 1, "led_data");
- break;
- }
+ return register_reboot_notifier(&lcd_system_halt_notifier);
}
-
-/*
- **
- ** lcd_print()
- **
- ** Displays the given string on the LCD-Display of newer machines.
- ** lcd_print() disables/enables the timer-based led work queue to
- ** avoid a race condition while writing the CMD/DATA register pair.
- **
- */
-int lcd_print( const char *str )
-{
- int i;
-
- if (!led_func_ptr || lcd_info.model != DISPLAY_MODEL_LCD)
- return 0;
-
- /* temporarily disable the led work task */
- if (led_wq)
- cancel_delayed_work_sync(&led_task);
-
- /* copy display string to buffer for procfs */
- strlcpy(lcd_text, str, sizeof(lcd_text));
-
- /* Set LCD Cursor to 1st character */
- gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG);
- udelay(lcd_info.min_cmd_delay);
-
- /* Print the string */
- for (i=0; i < lcd_info.lcd_width; i++) {
- if (str && *str)
- gsc_writeb(*str++, LCD_DATA_REG);
- else
- gsc_writeb(' ', LCD_DATA_REG);
- udelay(lcd_info.min_cmd_delay);
- }
-
- /* re-queue the work */
- if (led_wq) {
- queue_delayed_work(led_wq, &led_task, 0);
- }
-
- return lcd_info.lcd_width;
-}
-
-/*
- ** led_init()
- **
- ** led_init() is called very early in the bootup-process from setup.c
- ** and asks the PDC for an usable chassis LCD or LED.
- ** If the PDC doesn't return any info, then the LED
- ** is detected by lasi.c or asp.c and registered with the
- ** above functions lasi_led_init() or asp_led_init().
- ** KittyHawk machines have often a buggy PDC, so that
- ** we explicitly check for those machines here.
+/**
+ * early_led_init()
+ *
+ * early_led_init() is called early in the bootup-process and asks the
+ * PDC for an usable chassis LCD or LED. If the PDC doesn't return any
+ * info, then a LED might be detected by the LASI or ASP drivers later.
+ * KittyHawk machines have often a buggy PDC, so that we explicitly check
+ * for those machines here.
*/
-
-int __init led_init(void)
+static int __init early_led_init(void)
{
struct pdc_chassis_info chassis_info;
int ret;
- snprintf(lcd_text_default, sizeof(lcd_text_default),
+ scnprintf(lcd_text, sizeof(lcd_text),
"Linux %s", init_utsname()->release);
+ lcd_new_text = 1;
/* Work around the buggy PDC of KittyHawk-machines */
switch (CPU_HVERSION) {
@@ -698,82 +466,86 @@ int __init led_init(void)
case 0x582: /* KittyHawk DC3 100 (K400) */
case 0x583: /* KittyHawk DC3 120 (K410) */
case 0x58B: /* KittyHawk DC2 100 (K200) */
- printk(KERN_INFO "%s: KittyHawk-Machine (hversion 0x%x) found, "
- "LED detection skipped.\n", __FILE__, CPU_HVERSION);
+ pr_info("LCD on KittyHawk-Machine found.\n");
+ lcd_info.model = DISPLAY_MODEL_LCD;
+ /* KittyHawk has no LED support on its LCD, so skip LED detection */
lcd_no_led_support = 1;
goto found; /* use the preinitialized values of lcd_info */
}
/* initialize the struct, so that we can check for valid return values */
- lcd_info.model = DISPLAY_MODEL_NONE;
chassis_info.actcnt = chassis_info.maxcnt = 0;
ret = pdc_chassis_info(&chassis_info, &lcd_info, sizeof(lcd_info));
- if (ret == PDC_OK) {
- DPRINTK((KERN_INFO "%s: chassis info: model=%d (%s), "
- "lcd_width=%d, cmd_delay=%u,\n"
- "%s: sizecnt=%d, actcnt=%ld, maxcnt=%ld\n",
- __FILE__, lcd_info.model,
- (lcd_info.model==DISPLAY_MODEL_LCD) ? "LCD" :
- (lcd_info.model==DISPLAY_MODEL_LASI) ? "LED" : "unknown",
- lcd_info.lcd_width, lcd_info.min_cmd_delay,
- __FILE__, sizeof(lcd_info),
- chassis_info.actcnt, chassis_info.maxcnt));
- DPRINTK((KERN_INFO "%s: cmd=%p, data=%p, reset1=%x, reset2=%x, act_enable=%d\n",
- __FILE__, lcd_info.lcd_cmd_reg_addr,
- lcd_info.lcd_data_reg_addr, lcd_info.reset_cmd1,
- lcd_info.reset_cmd2, lcd_info.act_enable ));
-
- /* check the results. Some machines have a buggy PDC */
- if (chassis_info.actcnt <= 0 || chassis_info.actcnt != chassis_info.maxcnt)
- goto not_found;
+ if (ret != PDC_OK) {
+not_found:
+ lcd_info.model = DISPLAY_MODEL_NONE;
+ return 1;
+ }
+
+ /* check the results. Some machines have a buggy PDC */
+ if (chassis_info.actcnt <= 0 || chassis_info.actcnt != chassis_info.maxcnt)
+ goto not_found;
- switch (lcd_info.model) {
- case DISPLAY_MODEL_LCD: /* LCD display */
- if (chassis_info.actcnt <
- offsetof(struct pdc_chassis_lcd_info_ret_block, _pad)-1)
- goto not_found;
- if (!lcd_info.act_enable) {
- DPRINTK((KERN_INFO "PDC prohibited usage of the LCD.\n"));
- goto not_found;
- }
- break;
-
- case DISPLAY_MODEL_NONE: /* no LED or LCD available */
- printk(KERN_INFO "PDC reported no LCD or LED.\n");
+ switch (lcd_info.model) {
+ case DISPLAY_MODEL_LCD: /* LCD display */
+ if (chassis_info.actcnt <
+ offsetof(struct pdc_chassis_lcd_info_ret_block, _pad)-1)
+ goto not_found;
+ if (!lcd_info.act_enable) {
+ /* PDC tells LCD should not be used. */
goto not_found;
+ }
+ break;
- case DISPLAY_MODEL_LASI: /* Lasi style 8 bit LED display */
- if (chassis_info.actcnt != 8 && chassis_info.actcnt != 32)
- goto not_found;
- break;
+ case DISPLAY_MODEL_NONE: /* no LED or LCD available */
+ goto not_found;
- default:
- printk(KERN_WARNING "PDC reported unknown LCD/LED model %d\n",
- lcd_info.model);
+ case DISPLAY_MODEL_LASI: /* Lasi style 8 bit LED display */
+ if (chassis_info.actcnt != 8 && chassis_info.actcnt != 32)
goto not_found;
- } /* switch() */
-
-found:
- /* register the LCD/LED driver */
- register_led_driver(lcd_info.model, LCD_CMD_REG, LCD_DATA_REG);
- return 0;
+ break;
- } else { /* if() */
- DPRINTK((KERN_INFO "pdc_chassis_info call failed with retval = %d\n", ret));
+ default:
+ pr_warn("PDC reported unknown LCD/LED model %d\n",
+ lcd_info.model);
+ goto not_found;
}
-not_found:
- lcd_info.model = DISPLAY_MODEL_NONE;
- return 1;
+found:
+ /* register the LCD/LED driver */
+ return register_led_driver(lcd_info.model, LCD_CMD_REG, LCD_DATA_REG);
}
+arch_initcall(early_led_init);
-static void __exit led_exit(void)
+/**
+ * register_led_regions()
+ *
+ * Register_led_regions() registers the LCD/LED regions for /procfs.
+ * At bootup - where the initialisation of the LCD/LED often happens
+ * not all internal structures of request_region() are properly set up,
+ * so that we delay the led-registration until after busdevices_init()
+ * has been executed.
+ */
+static void __init register_led_regions(void)
{
- unregister_reboot_notifier(&led_notifier);
- return;
+ switch (lcd_info.model) {
+ case DISPLAY_MODEL_LCD:
+ request_mem_region((unsigned long)LCD_CMD_REG, 1, "lcd_cmd");
+ request_mem_region((unsigned long)LCD_DATA_REG, 1, "lcd_data");
+ break;
+ case DISPLAY_MODEL_LASI:
+ case DISPLAY_MODEL_OLD_ASP:
+ request_mem_region((unsigned long)LED_DATA_REG, 1, "led_data");
+ break;
+ }
}
-#ifdef CONFIG_PROC_FS
-module_init(led_create_procfs)
-#endif
+static int __init startup_leds(void)
+{
+ if (platform_device_register(&platform_leds))
+ printk(KERN_INFO "LED: failed to register LEDs\n");
+ register_led_regions();
+ return 0;
+}
+device_initcall(startup_leds);
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index 0f54ab6260df..16f4496bca95 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -1,22 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Interfaces to retrieve and set PDC Stable options (firmware)
*
* Copyright (C) 2005-2006 Thibaut VARENE <varenet@parisc-linux.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- *
* DEV NOTE: the PDC Procedures reference states that:
* "A minimum of 96 bytes of Stable Storage is required. Providing more than
* 96 bytes of Stable Storage is optional [...]. Failure to provide the
@@ -27,7 +14,7 @@
* all) PA-RISC machines should have them. Anyway, for safety reasons, the
* following code can deal with just 96 bytes of Stable Storage, and all
* sizes between 96 and 192 bytes (provided they are multiple of struct
- * device_path size, eg: 128, 160 and 192) to provide full information.
+ * pdc_module_path size, eg: 128, 160 and 192) to provide full information.
* One last word: there's one path we can always count on: the primary path.
* Anything above 224 bytes is used for 'osdep2' OS-dependent storage area.
*
@@ -68,7 +55,7 @@
#include <asm/pdc.h>
#include <asm/page.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <asm/hardware.h>
#define PDCS_VERSION "0.30"
@@ -101,7 +88,7 @@ struct pdcspath_entry {
short ready; /* entry record is valid if != 0 */
unsigned long addr; /* entry address in stable storage */
char *name; /* entry name */
- struct device_path devpath; /* device path in parisc representation */
+ struct pdc_module_path devpath; /* device path in parisc representation */
struct device *dev; /* corresponding device */
struct kobject kobj;
};
@@ -151,7 +138,7 @@ struct pdcspath_attribute paths_attr_##_name = { \
static int
pdcspath_fetch(struct pdcspath_entry *entry)
{
- struct device_path *devpath;
+ struct pdc_module_path *devpath;
if (!entry)
return -EINVAL;
@@ -166,7 +153,7 @@ pdcspath_fetch(struct pdcspath_entry *entry)
return -EIO;
/* Find the matching device.
- NOTE: hardware_path overlays with device_path, so the nice cast can
+ NOTE: hardware_path overlays with pdc_module_path, so the nice cast can
be used */
entry->dev = hwpath_to_device((struct hardware_path *)devpath);
@@ -192,7 +179,7 @@ pdcspath_fetch(struct pdcspath_entry *entry)
static void
pdcspath_store(struct pdcspath_entry *entry)
{
- struct device_path *devpath;
+ struct pdc_module_path *devpath;
BUG_ON(!entry);
@@ -234,7 +221,7 @@ static ssize_t
pdcspath_hwpath_read(struct pdcspath_entry *entry, char *buf)
{
char *out = buf;
- struct device_path *devpath;
+ struct pdc_module_path *devpath;
short i;
if (!entry || !buf)
@@ -249,11 +236,11 @@ pdcspath_hwpath_read(struct pdcspath_entry *entry, char *buf)
return -ENODATA;
for (i = 0; i < 6; i++) {
- if (devpath->bc[i] >= 128)
+ if (devpath->path.bc[i] < 0)
continue;
- out += sprintf(out, "%u/", (unsigned char)devpath->bc[i]);
+ out += sprintf(out, "%d/", devpath->path.bc[i]);
}
- out += sprintf(out, "%u\n", (unsigned char)devpath->mod);
+ out += sprintf(out, "%u\n", (unsigned char)devpath->path.mod);
return out - buf;
}
@@ -278,7 +265,7 @@ pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t coun
{
struct hardware_path hwpath;
unsigned short i;
- char in[count+1], *temp;
+ char in[64], *temp;
struct device *dev;
int ret;
@@ -286,8 +273,8 @@ pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t coun
return -EINVAL;
/* We'll use a local copy of buf */
- memset(in, 0, count+1);
- strncpy(in, buf, count);
+ count = min_t(size_t, count, sizeof(in)-1);
+ strscpy(in, buf, count + 1);
/* Let's clean up the target. 0xff is a blank pattern */
memset(&hwpath, 0xff, sizeof(hwpath));
@@ -308,12 +295,12 @@ pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t coun
for (i=5; ((temp = strrchr(in, '/'))) && (temp-in > 0) && (likely(i)); i--) {
hwpath.bc[i] = simple_strtoul(temp+1, NULL, 10);
in[temp-in] = '\0';
- DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
+ DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.path.bc[i]);
}
/* Store the final field */
hwpath.bc[i] = simple_strtoul(in, NULL, 10);
- DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.bc[i]);
+ DPRINTK("%s: bc[%d]: %d\n", __func__, i, hwpath.path.bc[i]);
/* Now we check that the user isn't trying to lure us */
if (!(dev = hwpath_to_device((struct hardware_path *)&hwpath))) {
@@ -332,11 +319,11 @@ pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t coun
/* Update the symlink to the real device */
sysfs_remove_link(&entry->kobj, "device");
+ write_unlock(&entry->rw_lock);
+
ret = sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
WARN_ON(ret);
- write_unlock(&entry->rw_lock);
-
printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" path to \"%s\"\n",
entry->name, buf);
@@ -354,7 +341,7 @@ static ssize_t
pdcspath_layer_read(struct pdcspath_entry *entry, char *buf)
{
char *out = buf;
- struct device_path *devpath;
+ struct pdc_module_path *devpath;
short i;
if (!entry || !buf)
@@ -393,14 +380,14 @@ pdcspath_layer_write(struct pdcspath_entry *entry, const char *buf, size_t count
{
unsigned int layers[6]; /* device-specific info (ctlr#, unit#, ...) */
unsigned short i;
- char in[count+1], *temp;
+ char in[64], *temp;
if (!entry || !buf || !count)
return -EINVAL;
/* We'll use a local copy of buf */
- memset(in, 0, count+1);
- strncpy(in, buf, count);
+ count = min_t(size_t, count, sizeof(in)-1);
+ strscpy(in, buf, count + 1);
/* Let's clean up the target. 0 is a blank pattern */
memset(&layers, 0, sizeof(layers));
@@ -493,11 +480,12 @@ static struct attribute *paths_subsys_attrs[] = {
&paths_attr_layer.attr,
NULL,
};
+ATTRIBUTE_GROUPS(paths_subsys);
/* Specific kobject type for our PDC paths */
-static struct kobj_type ktype_pdcspath = {
+static const struct kobj_type ktype_pdcspath = {
.sysfs_ops = &pdcspath_attr_ops,
- .default_attrs = paths_subsys_attrs,
+ .default_groups = paths_subsys_groups,
};
/* We hard define the 4 types of path we expect to find */
@@ -521,6 +509,8 @@ static struct pdcspath_entry *pdcspath_entries[] = {
/**
* pdcs_size_read - Stable Storage size output.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The output buffer to write to.
*/
static ssize_t pdcs_size_read(struct kobject *kobj,
@@ -540,6 +530,8 @@ static ssize_t pdcs_size_read(struct kobject *kobj,
/**
* pdcs_auto_read - Stable Storage autoboot/search flag output.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The output buffer to write to.
* @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
*/
@@ -557,7 +549,7 @@ static ssize_t pdcs_auto_read(struct kobject *kobj,
pathentry = &pdcspath_entry_primary;
read_lock(&pathentry->rw_lock);
- out += sprintf(out, "%s\n", (pathentry->devpath.flags & knob) ?
+ out += sprintf(out, "%s\n", (pathentry->devpath.path.flags & knob) ?
"On" : "Off");
read_unlock(&pathentry->rw_lock);
@@ -566,6 +558,8 @@ static ssize_t pdcs_auto_read(struct kobject *kobj,
/**
* pdcs_autoboot_read - Stable Storage autoboot flag output.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The output buffer to write to.
*/
static ssize_t pdcs_autoboot_read(struct kobject *kobj,
@@ -576,6 +570,8 @@ static ssize_t pdcs_autoboot_read(struct kobject *kobj,
/**
* pdcs_autosearch_read - Stable Storage autoboot flag output.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The output buffer to write to.
*/
static ssize_t pdcs_autosearch_read(struct kobject *kobj,
@@ -586,6 +582,8 @@ static ssize_t pdcs_autosearch_read(struct kobject *kobj,
/**
* pdcs_timer_read - Stable Storage timer count output (in seconds).
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The output buffer to write to.
*
* The value of the timer field correponds to a number of seconds in powers of 2.
@@ -604,8 +602,8 @@ static ssize_t pdcs_timer_read(struct kobject *kobj,
/* print the timer value in seconds */
read_lock(&pathentry->rw_lock);
- out += sprintf(out, "%u\n", (pathentry->devpath.flags & PF_TIMER) ?
- (1 << (pathentry->devpath.flags & PF_TIMER)) : 0);
+ out += sprintf(out, "%u\n", (pathentry->devpath.path.flags & PF_TIMER) ?
+ (1 << (pathentry->devpath.path.flags & PF_TIMER)) : 0);
read_unlock(&pathentry->rw_lock);
return out - buf;
@@ -613,6 +611,8 @@ static ssize_t pdcs_timer_read(struct kobject *kobj,
/**
* pdcs_osid_read - Stable Storage OS ID register output.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The output buffer to write to.
*/
static ssize_t pdcs_osid_read(struct kobject *kobj,
@@ -631,6 +631,8 @@ static ssize_t pdcs_osid_read(struct kobject *kobj,
/**
* pdcs_osdep1_read - Stable Storage OS-Dependent data area 1 output.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The output buffer to write to.
*
* This can hold 16 bytes of OS-Dependent data.
@@ -657,6 +659,8 @@ static ssize_t pdcs_osdep1_read(struct kobject *kobj,
/**
* pdcs_diagnostic_read - Stable Storage Diagnostic register output.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The output buffer to write to.
*
* I have NFC how to interpret the content of that register ;-).
@@ -681,6 +685,8 @@ static ssize_t pdcs_diagnostic_read(struct kobject *kobj,
/**
* pdcs_fastsize_read - Stable Storage FastSize register output.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The output buffer to write to.
*
* This register holds the amount of system RAM to be tested during boot sequence.
@@ -709,6 +715,8 @@ static ssize_t pdcs_fastsize_read(struct kobject *kobj,
/**
* pdcs_osdep2_read - Stable Storage OS-Dependent data area 2 output.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The output buffer to write to.
*
* This can hold pdcs_size - 224 bytes of OS-Dependent data, when available.
@@ -741,6 +749,8 @@ static ssize_t pdcs_osdep2_read(struct kobject *kobj,
/**
* pdcs_auto_write - This function handles autoboot/search flag modifying.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
* @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
@@ -755,7 +765,7 @@ static ssize_t pdcs_auto_write(struct kobject *kobj,
{
struct pdcspath_entry *pathentry;
unsigned char flags;
- char in[count+1], *temp;
+ char in[8], *temp;
char c;
if (!capable(CAP_SYS_ADMIN))
@@ -765,15 +775,15 @@ static ssize_t pdcs_auto_write(struct kobject *kobj,
return -EINVAL;
/* We'll use a local copy of buf */
- memset(in, 0, count+1);
- strncpy(in, buf, count);
+ count = min_t(size_t, count, sizeof(in)-1);
+ strscpy(in, buf, count + 1);
/* Current flags are stored in primary boot path entry */
pathentry = &pdcspath_entry_primary;
/* Be nice to the existing flag record */
read_lock(&pathentry->rw_lock);
- flags = pathentry->devpath.flags;
+ flags = pathentry->devpath.path.flags;
read_unlock(&pathentry->rw_lock);
DPRINTK("%s: flags before: 0x%X\n", __func__, flags);
@@ -794,7 +804,7 @@ static ssize_t pdcs_auto_write(struct kobject *kobj,
write_lock(&pathentry->rw_lock);
/* Change the path entry flags first */
- pathentry->devpath.flags = flags;
+ pathentry->devpath.path.flags = flags;
/* Now, dive in. Write back to the hardware */
pdcspath_store(pathentry);
@@ -813,6 +823,8 @@ parse_error:
/**
* pdcs_autoboot_write - This function handles autoboot flag modifying.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
*
@@ -829,6 +841,8 @@ static ssize_t pdcs_autoboot_write(struct kobject *kobj,
/**
* pdcs_autosearch_write - This function handles autosearch flag modifying.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
*
@@ -845,6 +859,8 @@ static ssize_t pdcs_autosearch_write(struct kobject *kobj,
/**
* pdcs_osdep1_write - Stable Storage OS-Dependent data area 1 input.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
*
@@ -882,6 +898,8 @@ static ssize_t pdcs_osdep1_write(struct kobject *kobj,
/**
* pdcs_osdep2_write - Stable Storage OS-Dependent data area 2 input.
+ * @kobj: The kobject used to share data with userspace.
+ * @attr: The kobject attributes.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
*
@@ -951,7 +969,7 @@ static struct attribute *pdcs_subsys_attrs[] = {
NULL,
};
-static struct attribute_group pdcs_attr_group = {
+static const struct attribute_group pdcs_attr_group = {
.attrs = pdcs_subsys_attrs,
};
@@ -989,12 +1007,15 @@ pdcs_register_pathentries(void)
entry->kobj.kset = paths_kset;
err = kobject_init_and_add(&entry->kobj, &ktype_pdcspath, NULL,
"%s", entry->name);
- if (err)
+ if (err) {
+ kobject_put(&entry->kobj);
return err;
+ }
/* kobject is now registered */
write_lock(&entry->rw_lock);
entry->ready = 2;
+ write_unlock(&entry->rw_lock);
/* Add a nice symlink to the real device */
if (entry->dev) {
@@ -1002,7 +1023,6 @@ pdcs_register_pathentries(void)
WARN_ON(err);
}
- write_unlock(&entry->rw_lock);
kobject_uevent(&entry->kobj, KOBJ_ADD);
}
@@ -1033,7 +1053,7 @@ pdcs_unregister_pathentries(void)
static int __init
pdc_stable_init(void)
{
- int rc = 0, error = 0;
+ int rc = 0, error;
u32 result;
/* find the size of the stable storage */
@@ -1062,6 +1082,10 @@ pdc_stable_init(void)
/* Don't forget the root entries */
error = sysfs_create_group(stable_kobj, &pdcs_attr_group);
+ if (error) {
+ rc = -ENOMEM;
+ goto fail_ksetreg;
+ }
/* register the paths kset as a child of the stable kset */
paths_kset = kset_create_and_add("paths", NULL, stable_kobj);
diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c
index 90cca5e3805f..9d6c7bf72e29 100644
--- a/drivers/parisc/power.c
+++ b/drivers/parisc/power.c
@@ -1,45 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- * linux/drivers/parisc/power.c
- * HP PARISC soft power switch support driver
- *
- * Copyright (c) 2001-2007 Helge Deller <deller@gmx.de>
- * All rights reserved.
- *
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions, and the following disclaimer,
- * without modification.
- * 2. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * Alternatively, this software may be distributed under the terms of the
- * GNU General Public License ("GPL").
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * HP PARISC soft power switch driver
*
+ * Copyright (c) 2001-2023 Helge Deller <deller@gmx.de>
*
* HINT:
* Support of the soft power switch button may be enabled or disabled at
* runtime through the "/proc/sys/kernel/power" procfs entry.
- */
+ */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/notifier.h>
+#include <linux/panic_notifier.h>
#include <linux/reboot.h>
-#include <linux/sched.h>
+#include <linux/sched/signal.h>
#include <linux/kthread.h>
#include <linux/pm.h>
@@ -62,12 +37,12 @@
#define MFCPU_X(rDiagReg, t_ch, t_th, code) \
(DIAG_CODE(code) + ((rDiagReg)<<21) + ((t_ch)<<16) + ((t_th)<<0) )
-
+
#define MTCPU(dr, gr) MFCPU_X(dr, gr, 0, 0x12) /* move value of gr to dr[dr] */
#define MFCPU_C(dr, gr) MFCPU_X(dr, gr, 0, 0x30) /* for dr0 and dr8 only ! */
#define MFCPU_T(dr, gr) MFCPU_X(dr, 0, gr, 0xa0) /* all dr except dr0 and dr8 */
-
-#define __getDIAG(dr) ( { \
+
+#define __getDIAG(dr) ( { \
register unsigned long __res asm("r28");\
__asm__ __volatile__ ( \
".word %1" : "=&r" (__res) : "i" (MFCPU_T(dr,28) ) \
@@ -85,7 +60,7 @@ static void process_shutdown(void)
printk(KERN_ALERT KTHREAD_NAME ": Shutdown requested...\n");
shutdown_timer++;
-
+
/* wait until the button was pressed for 1 second */
if (shutdown_timer == (POWERSWITCH_DOWN_SEC*POWERSWITCH_POLL_PER_SEC)) {
static const char msg[] = "Shutting down...";
@@ -95,8 +70,7 @@ static void process_shutdown(void)
/* send kill signal */
if (kill_cad_pid(SIGINT, 1)) {
/* just in case killing init process failed */
- if (pm_power_off)
- pm_power_off();
+ machine_power_off();
}
}
}
@@ -109,7 +83,25 @@ static struct task_struct *power_task;
#define SYSCTL_FILENAME "sys/kernel/power"
/* soft power switch enabled/disabled */
-int pwrsw_enabled __read_mostly = 1;
+static int pwrsw_enabled __read_mostly = 1;
+
+static const struct ctl_table power_sysctl_table[] = {
+ {
+ .procname = "soft-power",
+ .data = &pwrsw_enabled,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec,
+ },
+};
+
+static int __init init_power_sysctl(void)
+{
+ register_sysctl_init("kernel", power_sysctl_table);
+ return 0;
+}
+
+arch_initcall(init_power_sysctl);
/* main kernel thread worker. It polls the button state */
static int kpowerswd(void *param)
@@ -121,7 +113,6 @@ static int kpowerswd(void *param)
unsigned long soft_power_reg = (unsigned long) param;
schedule_timeout_interruptible(pwrsw_enabled ? HZ : HZ/POWERSWITCH_POLL_PER_SEC);
- __set_current_state(TASK_RUNNING);
if (unlikely(!pwrsw_enabled))
continue;
@@ -137,7 +128,7 @@ static int kpowerswd(void *param)
button_not_pressed = (gsc_readl(soft_power_reg) & 0x1);
} else {
/*
- * On gecko style machines (e.g. 712/xx and 715/xx)
+ * On gecko style machines (e.g. 712/xx and 715/xx)
* the power switch status is stored in Bit 0 ("the highest bit")
* of CPU diagnose register 25.
* Warning: Some machines never reset the DIAG flag, even if
@@ -163,7 +154,7 @@ static int kpowerswd(void *param)
/*
- * powerfail interruption handler (irq IRQ_FROM_REGION(CPU_IRQ_REGION)+2)
+ * powerfail interruption handler (irq IRQ_FROM_REGION(CPU_IRQ_REGION)+2)
*/
#if 0
static void powerfail_interrupt(int code, void *x)
@@ -176,16 +167,21 @@ static void powerfail_interrupt(int code, void *x)
-/* parisc_panic_event() is called by the panic handler.
- * As soon as a panic occurs, our tasklets above will not be
- * executed any longer. This function then re-enables the
- * soft-power switch and allows the user to switch off the system
+/*
+ * parisc_panic_event() is called by the panic handler.
+ *
+ * As soon as a panic occurs, our tasklets above will not
+ * be executed any longer. This function then re-enables
+ * the soft-power switch and allows the user to switch off
+ * the system. We rely in pdc_soft_power_button_panic()
+ * since this version spin_trylocks (instead of regular
+ * spinlock), preventing deadlocks on panic path.
*/
static int parisc_panic_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
/* re-enable the soft-power switch */
- pdc_soft_power_button(0);
+ pdc_soft_power_button_panic(0);
return NOTIFY_DONE;
}
@@ -194,6 +190,14 @@ static struct notifier_block parisc_panic_block = {
.priority = INT_MAX,
};
+/* qemu soft power-off function */
+static int qemu_power_off(struct sys_off_data *data)
+{
+ /* this turns the system off via SeaBIOS */
+ gsc_writel(0, (unsigned long) data->cb_data);
+ pdc_soft_power_button(1);
+ return NOTIFY_DONE;
+}
static int __init power_init(void)
{
@@ -211,19 +215,25 @@ static int __init power_init(void)
ret = pdc_soft_power_button(1);
if (ret != PDC_OK)
soft_power_reg = -1UL;
-
+
switch (soft_power_reg) {
case 0: printk(KERN_INFO DRIVER_NAME ": Gecko-style soft power switch enabled.\n");
break;
-
+
case -1UL: printk(KERN_INFO DRIVER_NAME ": Soft power switch support not available.\n");
return -ENODEV;
-
+
default: printk(KERN_INFO DRIVER_NAME ": Soft power switch at 0x%08lx enabled.\n",
soft_power_reg);
}
- power_task = kthread_run(kpowerswd, (void*)soft_power_reg, KTHREAD_NAME);
+ power_task = NULL;
+ if (running_on_qemu && soft_power_reg)
+ register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_DEFAULT,
+ qemu_power_off, (void *)soft_power_reg);
+ if (!running_on_qemu || soft_power_reg)
+ power_task = kthread_run(kpowerswd, (void*)soft_power_reg,
+ KTHREAD_NAME);
if (IS_ERR(power_task)) {
printk(KERN_ERR DRIVER_NAME ": thread creation failed. Driver not loaded.\n");
pdc_soft_power_button(0);
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 1ff1b67e8b27..a6eb6bffa5ea 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
** System Bus Adapter (SBA) I/O MMU manager
**
@@ -7,10 +8,6 @@
**
** Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code)
**
-** This program is free software; you can redistribute it and/or modify
-** it under the terms of the GNU General Public License as published by
-** the Free Software Foundation; either version 2 of the License, or
-** (at your option) any later version.
**
**
** This module initializes the IOC (I/O Controller) found on B1000/C3000/
@@ -28,8 +25,15 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/pci.h>
+#include <linux/dma-map-ops.h>
#include <linux/scatterlist.h>
#include <linux/iommu-helper.h>
+/*
+ * The semantics of 64 register access on 32bit systems can't be guaranteed
+ * by the C standard, we hope the _lo_hi() macros defining readq and writeq
+ * here will behave as expected.
+ */
+#include <linux/io-64-nonatomic-lo-hi.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -42,13 +46,13 @@
#include <linux/module.h>
#include <asm/ropes.h>
-#include <asm/mckinley.h> /* for proc_mckinley_root */
-#include <asm/runway.h> /* for proc_runway_root */
#include <asm/page.h> /* for PAGE0 */
#include <asm/pdc.h> /* for PDC_MODEL_* */
#include <asm/pdcpat.h> /* for is_pdc_pat() */
#include <asm/parisc-device.h>
+#include "iommu.h"
+
#define MODULE_NAME "SBA"
/*
@@ -89,8 +93,6 @@
#define DBG_RES(x...)
#endif
-#define SBA_INLINE __inline__
-
#define DEFAULT_DMA_HINT_REG 0
struct sba_device *sba_list;
@@ -117,6 +119,8 @@ module_param(sba_reserve_agpgart, int, 0444);
MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART");
#endif
+static struct proc_dir_entry *proc_runway_root __ro_after_init;
+static struct proc_dir_entry *proc_mckinley_root __ro_after_init;
/************************************
** SBA register read and write support
@@ -198,7 +202,7 @@ static void
sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide)
{
/* start printing from lowest pde in rval */
- u64 *ptr = &(ioc->pdir_base[pide & (~0U * BITS_PER_LONG)]);
+ __le64 *ptr = &(ioc->pdir_base[pide & (~0U * BITS_PER_LONG)]);
unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]);
uint rcnt;
@@ -278,7 +282,7 @@ sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
nents,
(unsigned long) sg_dma_address(startsg),
sg_dma_len(startsg),
- sg_virt_addr(startsg), startsg->length);
+ sg_virt(startsg), startsg->length);
startsg++;
}
}
@@ -326,13 +330,14 @@ static unsigned long ptr_to_pide(struct ioc *ioc, unsigned long *res_ptr,
/**
* sba_search_bitmap - find free space in IO PDIR resource bitmap
* @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @dev: device to query the bitmap for
* @bits_wanted: number of entries we need.
*
* Find consecutive free bits in resource bitmap.
* Each bit represents one entry in the IO Pdir.
* Cool perf optimization: search for log2(size) bits at a time.
*/
-static SBA_INLINE unsigned long
+static unsigned long
sba_search_bitmap(struct ioc *ioc, struct device *dev,
unsigned long bits_wanted)
{
@@ -343,8 +348,7 @@ sba_search_bitmap(struct ioc *ioc, struct device *dev,
unsigned long shift;
int ret;
- boundary_size = ALIGN((unsigned long long)dma_get_seg_boundary(dev) + 1,
- 1ULL << IOVP_SHIFT) >> IOVP_SHIFT;
+ boundary_size = dma_get_seg_boundary_nr_pages(dev, IOVP_SHIFT);
#if defined(ZX1_SUPPORT)
BUG_ON(ioc->ibase & ~IOVP_MASK);
@@ -426,6 +430,7 @@ sba_search_bitmap(struct ioc *ioc, struct device *dev,
/**
* sba_alloc_range - find free bits and mark them in IO PDIR resource bitmap
* @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @dev: device for which pages should be alloced
* @size: number of bytes to create a mapping for
*
* Given a size, find consecutive unmarked and then mark those bits in the
@@ -485,7 +490,7 @@ sba_alloc_range(struct ioc *ioc, struct device *dev, size_t size)
*
* clear bits in the ioc's resource map
*/
-static SBA_INLINE void
+static void
sba_free_range(struct ioc *ioc, dma_addr_t iova, size_t size)
{
unsigned long iovp = SBA_IOVP(ioc, iova);
@@ -527,7 +532,7 @@ typedef unsigned long space_t;
* sba_io_pdir_entry - fill in one IO PDIR entry
* @pdir_ptr: pointer to IO PDIR entry
* @sid: process Space ID - currently only support KERNEL_SPACE
- * @vba: Virtual CPU address of buffer to map
+ * @pba: Physical address of buffer to map
* @hint: DMA hint set to use for this mapping
*
* SBA Mapping Routine
@@ -563,30 +568,25 @@ typedef unsigned long space_t;
* IOMMU uses little endian for the pdir.
*/
-static void SBA_INLINE
-sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
+static void
+sba_io_pdir_entry(__le64 *pdir_ptr, space_t sid, phys_addr_t pba,
unsigned long hint)
{
- u64 pa; /* physical address */
register unsigned ci; /* coherent index */
- pa = virt_to_phys(vba);
- pa &= IOVP_MASK;
+ asm("lci 0(%1), %0" : "=r" (ci) : "r" (phys_to_virt(pba)));
+ pba &= IOVP_MASK;
+ pba |= (ci >> PAGE_SHIFT) & 0xff; /* move CI (8 bits) into lowest byte */
- mtsp(sid,1);
- asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
- pa |= (ci >> PAGE_SHIFT) & 0xff; /* move CI (8 bits) into lowest byte */
-
- pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */
- *pdir_ptr = cpu_to_le64(pa); /* swap and store into I/O Pdir */
+ pba |= SBA_PDIR_VALID_BIT; /* set "valid" bit */
+ *pdir_ptr = cpu_to_le64(pba); /* swap and store into I/O Pdir */
/*
* If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit set
* (bit #61, big endian), we have to flush and sync every time
* IO-PDIR is changed in Ike/Astro.
*/
- if (ioc_needs_fdc)
- asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
+ asm_io_fdc(pdir_ptr);
}
@@ -606,11 +606,11 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
* must be a power of 2. The "Cool perf optimization" in the
* allocation routine helps keep that true.
*/
-static SBA_INLINE void
+static void
sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
{
u32 iovp = (u32) SBA_IOVP(ioc,iova);
- u64 *pdir_ptr = &ioc->pdir_base[PDIR_INDEX(iovp)];
+ __le64 *pdir_ptr = &ioc->pdir_base[PDIR_INDEX(iovp)];
#ifdef ASSERT_PDIR_SANITY
/* Assert first pdir entry is set.
@@ -639,8 +639,8 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
do {
/* clear I/O Pdir entry "valid" bit first */
((u8 *) pdir_ptr)[7] = 0;
+ asm_io_fdc(pdir_ptr);
if (ioc_needs_fdc) {
- asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
#if 0
entries_per_cacheline = L1_CACHE_SHIFT - 3;
#endif
@@ -659,8 +659,7 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
** could dump core on HPMC.
*/
((u8 *) pdir_ptr)[7] = 0;
- if (ioc_needs_fdc)
- asm volatile("fdc %%r0(%0)" : : "r" (pdir_ptr));
+ asm_io_fdc(pdir_ptr);
WRITE_REG( SBA_IOVA(ioc, iovp, 0, 0), ioc->ioc_hpa+IOC_PCOM);
}
@@ -670,7 +669,7 @@ sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
* @dev: instance of PCI owned by the driver that's asking
* @mask: number of address bits this PCI device can handle
*
- * See Documentation/DMA-API-HOWTO.txt
+ * See Documentation/core-api/dma-api-howto.rst
*/
static int sba_dma_supported( struct device *dev, u64 mask)
{
@@ -682,15 +681,9 @@ static int sba_dma_supported( struct device *dev, u64 mask)
return(0);
}
- /* Documentation/DMA-API-HOWTO.txt tells drivers to try 64-bit
- * first, then fall back to 32-bit if that fails.
- * We are just "encouraging" 32-bit DMA masks here since we can
- * never allow IOMMU bypass unless we add special support for ZX1.
- */
- if (mask > ~0U)
- return 0;
-
ioc = GET_IOC(dev);
+ if (!ioc)
+ return 0;
/*
* check if mask is >= than the current max IO Virt Address
@@ -708,23 +701,25 @@ static int sba_dma_supported( struct device *dev, u64 mask)
* @size: number of bytes to map in driver buffer.
* @direction: R/W or both.
*
- * See Documentation/DMA-API-HOWTO.txt
+ * See Documentation/core-api/dma-api-howto.rst
*/
static dma_addr_t
-sba_map_single(struct device *dev, void *addr, size_t size,
+sba_map_single(struct device *dev, phys_addr_t addr, size_t size,
enum dma_data_direction direction)
{
struct ioc *ioc;
unsigned long flags;
dma_addr_t iovp;
dma_addr_t offset;
- u64 *pdir_start;
+ __le64 *pdir_start;
int pide;
ioc = GET_IOC(dev);
+ if (!ioc)
+ return DMA_MAPPING_ERROR;
/* save offset bits */
- offset = ((dma_addr_t) (long) addr) & ~IOVP_MASK;
+ offset = offset_in_page(addr);
/* round up to nearest IOVP_SIZE */
size = (size + offset + ~IOVP_MASK) & IOVP_MASK;
@@ -741,13 +736,13 @@ sba_map_single(struct device *dev, void *addr, size_t size,
pide = sba_alloc_range(ioc, dev, size);
iovp = (dma_addr_t) pide << IOVP_SHIFT;
- DBG_RUN("%s() 0x%p -> 0x%lx\n",
- __func__, addr, (long) iovp | offset);
+ DBG_RUN("%s() 0x%pa -> 0x%lx\n",
+ __func__, &addr, (long) iovp | offset);
pdir_start = &(ioc->pdir_base[pide]);
while (size > 0) {
- sba_io_pdir_entry(pdir_start, KERNEL_SPACE, (unsigned long) addr, 0);
+ sba_io_pdir_entry(pdir_start, KERNEL_SPACE, addr, 0);
DBG_RUN(" pdir 0x%p %02x%02x%02x%02x%02x%02x%02x%02x\n",
pdir_start,
@@ -767,8 +762,7 @@ sba_map_single(struct device *dev, void *addr, size_t size,
}
/* force FDC ops in io_pdir_entry() to be visible to IOMMU */
- if (ioc_needs_fdc)
- asm volatile("sync" : : );
+ asm_io_sync();
#ifdef ASSERT_PDIR_SANITY
sba_check_pdir(ioc,"Check after sba_map_single()");
@@ -780,18 +774,30 @@ sba_map_single(struct device *dev, void *addr, size_t size,
}
+static dma_addr_t
+sba_map_phys(struct device *dev, phys_addr_t phys, size_t size,
+ enum dma_data_direction direction, unsigned long attrs)
+{
+ if (unlikely(attrs & DMA_ATTR_MMIO))
+ return DMA_MAPPING_ERROR;
+
+ return sba_map_single(dev, phys, size, direction);
+}
+
+
/**
- * sba_unmap_single - unmap one IOVA and free resources
+ * sba_unmap_phys - unmap one IOVA and free resources
* @dev: instance of PCI owned by the driver that's asking.
* @iova: IOVA of driver buffer previously mapped.
* @size: number of bytes mapped in driver buffer.
* @direction: R/W or both.
+ * @attrs: attributes
*
- * See Documentation/DMA-API-HOWTO.txt
+ * See Documentation/core-api/dma-api-howto.rst
*/
static void
-sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
- enum dma_data_direction direction)
+sba_unmap_phys(struct device *dev, dma_addr_t iova, size_t size,
+ enum dma_data_direction direction, unsigned long attrs)
{
struct ioc *ioc;
#if DELAYED_RESOURCE_CNT > 0
@@ -803,6 +809,10 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
DBG_RUN("%s() iovp 0x%lx/%x\n", __func__, (long) iova, size);
ioc = GET_IOC(dev);
+ if (!ioc) {
+ WARN_ON(!ioc);
+ return;
+ }
offset = iova & ~IOVP_MASK;
iova ^= offset; /* clear offset bits */
size += offset;
@@ -838,8 +848,7 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
sba_free_range(ioc, iova, size);
/* If fdc's were issued, force fdc's to be visible now */
- if (ioc_needs_fdc)
- asm volatile("sync" : : );
+ asm_io_sync();
READ_REG(ioc->ioc_hpa+IOC_PCOM); /* flush purges */
#endif /* DELAYED_RESOURCE_CNT == 0 */
@@ -858,15 +867,17 @@ sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size,
/**
- * sba_alloc_consistent - allocate/map shared mem for DMA
+ * sba_alloc - allocate/map shared mem for DMA
* @hwdev: instance of PCI owned by the driver that's asking.
* @size: number of bytes mapped in driver buffer.
* @dma_handle: IOVA of new buffer.
+ * @gfp: allocation flags
+ * @attrs: attributes
*
- * See Documentation/DMA-API-HOWTO.txt
+ * See Documentation/core-api/dma-api-howto.rst
*/
-static void *sba_alloc_consistent(struct device *hwdev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp)
+static void *sba_alloc(struct device *hwdev, size_t size, dma_addr_t *dma_handle,
+ gfp_t gfp, unsigned long attrs)
{
void *ret;
@@ -880,7 +891,7 @@ static void *sba_alloc_consistent(struct device *hwdev, size_t size,
if (ret) {
memset(ret, 0, size);
- *dma_handle = sba_map_single(hwdev, ret, size, 0);
+ *dma_handle = sba_map_single(hwdev, virt_to_phys(ret), size, 0);
}
return ret;
@@ -888,19 +899,20 @@ static void *sba_alloc_consistent(struct device *hwdev, size_t size,
/**
- * sba_free_consistent - free/unmap shared mem for DMA
+ * sba_free - free/unmap shared mem for DMA
* @hwdev: instance of PCI owned by the driver that's asking.
* @size: number of bytes mapped in driver buffer.
* @vaddr: virtual address IOVA of "consistent" buffer.
- * @dma_handler: IO virtual address of "consistent" buffer.
+ * @dma_handle: IO virtual address of "consistent" buffer.
+ * @attrs: attributes
*
- * See Documentation/DMA-API-HOWTO.txt
+ * See Documentation/core-api/dma-api-howto.rst
*/
static void
-sba_free_consistent(struct device *hwdev, size_t size, void *vaddr,
- dma_addr_t dma_handle)
+sba_free(struct device *hwdev, size_t size, void *vaddr,
+ dma_addr_t dma_handle, unsigned long attrs)
{
- sba_unmap_single(hwdev, dma_handle, size, 0);
+ sba_unmap_phys(hwdev, dma_handle, size, 0, 0);
free_pages((unsigned long) vaddr, get_order(size));
}
@@ -928,25 +940,27 @@ int dump_run_sg = 0;
* @sglist: array of buffer/length pairs
* @nents: number of entries in list
* @direction: R/W or both.
+ * @attrs: attributes
*
- * See Documentation/DMA-API-HOWTO.txt
+ * See Documentation/core-api/dma-api-howto.rst
*/
static int
sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
- enum dma_data_direction direction)
+ enum dma_data_direction direction, unsigned long attrs)
{
struct ioc *ioc;
- int coalesced, filled = 0;
+ int filled = 0;
unsigned long flags;
DBG_RUN_SG("%s() START %d entries\n", __func__, nents);
ioc = GET_IOC(dev);
+ if (!ioc)
+ return -EINVAL;
/* Fast path single entry scatterlists. */
if (nents == 1) {
- sg_dma_address(sglist) = sba_map_single(dev,
- (void *)sg_virt_addr(sglist),
+ sg_dma_address(sglist) = sba_map_single(dev, sg_phys(sglist),
sglist->length, direction);
sg_dma_len(sglist) = sglist->length;
return 1;
@@ -974,7 +988,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
** w/o this association, we wouldn't have coherent DMA!
** Access to the virtual address is what forces a two pass algorithm.
*/
- coalesced = iommu_coalesce_chunks(ioc, dev, sglist, nents, sba_alloc_range);
+ iommu_coalesce_chunks(ioc, dev, sglist, nents, sba_alloc_range);
/*
** Program the I/O Pdir
@@ -987,8 +1001,7 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
filled = iommu_fill_pdir(ioc, sglist, nents, 0, sba_io_pdir_entry);
/* force FDC ops in io_pdir_entry() to be visible to IOMMU */
- if (ioc_needs_fdc)
- asm volatile("sync" : : );
+ asm_io_sync();
#ifdef ASSERT_PDIR_SANITY
if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
@@ -1012,12 +1025,13 @@ sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents,
* @sglist: array of buffer/length pairs
* @nents: number of entries in list
* @direction: R/W or both.
+ * @attrs: attributes
*
- * See Documentation/DMA-API-HOWTO.txt
+ * See Documentation/core-api/dma-api-howto.rst
*/
static void
sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
- enum dma_data_direction direction)
+ enum dma_data_direction direction, unsigned long attrs)
{
struct ioc *ioc;
#ifdef ASSERT_PDIR_SANITY
@@ -1025,9 +1039,13 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
#endif
DBG_RUN_SG("%s() START %d entries, %p,%x\n",
- __func__, nents, sg_virt_addr(sglist), sglist->length);
+ __func__, nents, sg_virt(sglist), sglist->length);
ioc = GET_IOC(dev);
+ if (!ioc) {
+ WARN_ON(!ioc);
+ return;
+ }
#ifdef SBA_COLLECT_STATS
ioc->usg_calls++;
@@ -1039,14 +1057,16 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
spin_unlock_irqrestore(&ioc->res_lock, flags);
#endif
- while (sg_dma_len(sglist) && nents--) {
+ while (nents && sg_dma_len(sglist)) {
- sba_unmap_single(dev, sg_dma_address(sglist), sg_dma_len(sglist), direction);
+ sba_unmap_phys(dev, sg_dma_address(sglist), sg_dma_len(sglist),
+ direction, 0);
#ifdef SBA_COLLECT_STATS
ioc->usg_pages += ((sg_dma_address(sglist) & ~IOVP_MASK) + sg_dma_len(sglist) + IOVP_SIZE - 1) >> PAGE_SHIFT;
ioc->usingle_calls--; /* kluge since call is unmap_sg() */
#endif
++sglist;
+ nents--;
}
DBG_RUN_SG("%s() DONE (nents %d)\n", __func__, nents);
@@ -1059,19 +1079,17 @@ sba_unmap_sg(struct device *dev, struct scatterlist *sglist, int nents,
}
-static struct hppa_dma_ops sba_ops = {
+static const struct dma_map_ops sba_ops = {
.dma_supported = sba_dma_supported,
- .alloc_consistent = sba_alloc_consistent,
- .alloc_noncoherent = sba_alloc_consistent,
- .free_consistent = sba_free_consistent,
- .map_single = sba_map_single,
- .unmap_single = sba_unmap_single,
+ .alloc = sba_alloc,
+ .free = sba_free,
+ .map_phys = sba_map_phys,
+ .unmap_phys = sba_unmap_phys,
.map_sg = sba_map_sg,
.unmap_sg = sba_unmap_sg,
- .dma_sync_single_for_cpu = NULL,
- .dma_sync_single_for_device = NULL,
- .dma_sync_sg_for_cpu = NULL,
- .dma_sync_sg_for_device = NULL,
+ .get_sgtable = dma_common_get_sgtable,
+ .alloc_pages_op = dma_common_alloc_pages,
+ .free_pages = dma_common_free_pages,
};
@@ -1215,8 +1233,6 @@ struct ibase_data_struct {
static int setup_ibase_imask_callback(struct device *dev, void *data)
{
- /* lba_set_iregs() is in drivers/parisc/lba_pci.c */
- extern void lba_set_iregs(struct parisc_device *, u32, u32);
struct parisc_device *lba = to_parisc_device(dev);
struct ibase_data_struct *ibd = data;
int rope_num = (lba->hpa.start >> 13) & 0xf;
@@ -1265,7 +1281,7 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
** (one that doesn't overlap memory or LMMIO space) in the
** IBASE and IMASK registers.
*/
- ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE);
+ ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & ~0x1fffffULL;
iova_space_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1;
if ((ioc->ibase < 0xfed00000UL) && ((ioc->ibase + iova_space_size) > 0xfee00000UL)) {
@@ -1392,7 +1408,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
** for DMA hints - ergo only 30 bits max.
*/
- iova_space_size = (u32) (totalram_pages/global_ioc_cnt);
+ iova_space_size = (u32) (totalram_pages()/global_ioc_cnt);
/* limit IOVA space size to 1MB-1GB */
if (iova_space_size < (1 << (20 - PAGE_SHIFT))) {
@@ -1414,10 +1430,10 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
- DBG_INIT("%s() hpa 0x%lx mem %ldMB IOV %dMB (%d bits)\n",
+ DBG_INIT("%s() hpa %px mem %ldMB IOV %dMB (%d bits)\n",
__func__,
ioc->ioc_hpa,
- (unsigned long) totalram_pages >> (20 - PAGE_SHIFT),
+ (unsigned long) totalram_pages() >> (20 - PAGE_SHIFT),
iova_space_size>>20,
iov_order + PAGE_SHIFT);
@@ -1451,7 +1467,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
ioc->iovp_mask = ~(iova_space_mask + PAGE_SIZE - 1);
#endif
- DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n",
+ DBG_INIT("%s() IOV base %#lx mask %#0lx\n",
__func__, ioc->ibase, ioc->imask);
/*
@@ -1508,7 +1524,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
static void __iomem *ioc_remap(struct sba_device *sba_dev, unsigned int offset)
{
- return ioremap_nocache(sba_dev->dev->hpa.start + offset, SBA_FUNC_SIZE);
+ return ioremap(sba_dev->dev->hpa.start + offset, SBA_FUNC_SIZE);
}
static void sba_hw_init(struct sba_device *sba_dev)
@@ -1563,7 +1579,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
if (!IS_PLUTO(sba_dev->dev)) {
ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
- DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
+ DBG_INIT("%s() hpa %px ioc_ctl 0x%Lx ->",
__func__, sba_dev->sba_hpa, ioc_ctl);
ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC | IOC_CTRL_CE);
ioc_ctl |= IOC_CTRL_DD | IOC_CTRL_D4 | IOC_CTRL_TC;
@@ -1648,14 +1664,14 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
/* flush out the last writes */
READ_REG(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL);
- DBG_INIT(" ioc[%d] ROPE_CFG 0x%Lx ROPE_DBG 0x%Lx\n",
+ DBG_INIT(" ioc[%d] ROPE_CFG %#lx ROPE_DBG %lx\n",
i,
- READ_REG(sba_dev->ioc[i].ioc_hpa + 0x40),
- READ_REG(sba_dev->ioc[i].ioc_hpa + 0x50)
+ (unsigned long) READ_REG(sba_dev->ioc[i].ioc_hpa + 0x40),
+ (unsigned long) READ_REG(sba_dev->ioc[i].ioc_hpa + 0x50)
);
- DBG_INIT(" STATUS_CONTROL 0x%Lx FLUSH_CTRL 0x%Lx\n",
- READ_REG(sba_dev->ioc[i].ioc_hpa + 0x108),
- READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400)
+ DBG_INIT(" STATUS_CONTROL %#lx FLUSH_CTRL %#lx\n",
+ (unsigned long) READ_REG(sba_dev->ioc[i].ioc_hpa + 0x108),
+ (unsigned long) READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400)
);
if (IS_PLUTO(sba_dev->dev)) {
@@ -1719,7 +1735,7 @@ sba_common_init(struct sba_device *sba_dev)
#ifdef ASSERT_PDIR_SANITY
/* Mark first bit busy - ie no IOVA 0 */
sba_dev->ioc[i].res_map[0] = 0x80;
- sba_dev->ioc[i].pdir_base[0] = 0xeeffc0addbba0080ULL;
+ sba_dev->ioc[i].pdir_base[0] = (__force __le64) 0xeeffc0addbba0080ULL;
#endif
/* Third (and last) part of PIRANHA BUG */
@@ -1774,37 +1790,35 @@ static int sba_proc_info(struct seq_file *m, void *p)
#ifdef SBA_COLLECT_STATS
unsigned long avg = 0, min, max;
#endif
- int i, len = 0;
-
- len += seq_printf(m, "%s rev %d.%d\n",
- sba_dev->name,
- (sba_dev->hw_rev & 0x7) + 1,
- (sba_dev->hw_rev & 0x18) >> 3
- );
- len += seq_printf(m, "IO PDIR size : %d bytes (%d entries)\n",
- (int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */
- total_pages);
-
- len += seq_printf(m, "Resource bitmap : %d bytes (%d pages)\n",
- ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */
-
- len += seq_printf(m, "LMMIO_BASE/MASK/ROUTE %08x %08x %08x\n",
- READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_BASE),
- READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_MASK),
- READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_ROUTE)
- );
+ int i;
+
+ seq_printf(m, "%s rev %d.%d\n",
+ sba_dev->name,
+ (sba_dev->hw_rev & 0x7) + 1,
+ (sba_dev->hw_rev & 0x18) >> 3);
+ seq_printf(m, "IO PDIR size : %d bytes (%d entries)\n",
+ (int)((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */
+ total_pages);
+
+ seq_printf(m, "Resource bitmap : %d bytes (%d pages)\n",
+ ioc->res_size, ioc->res_size << 3); /* 8 bits per byte */
+
+ seq_printf(m, "LMMIO_BASE/MASK/ROUTE %08x %08x %08x\n",
+ READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_BASE),
+ READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_MASK),
+ READ_REG32(sba_dev->sba_hpa + LMMIO_DIST_ROUTE));
for (i=0; i<4; i++)
- len += seq_printf(m, "DIR%d_BASE/MASK/ROUTE %08x %08x %08x\n", i,
- READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_BASE + i*0x18),
- READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_MASK + i*0x18),
- READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_ROUTE + i*0x18)
- );
+ seq_printf(m, "DIR%d_BASE/MASK/ROUTE %08x %08x %08x\n",
+ i,
+ READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_BASE + i*0x18),
+ READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_MASK + i*0x18),
+ READ_REG32(sba_dev->sba_hpa + LMMIO_DIRECT0_ROUTE + i*0x18));
#ifdef SBA_COLLECT_STATS
- len += seq_printf(m, "IO PDIR entries : %ld free %ld used (%d%%)\n",
- total_pages - ioc->used_pages, ioc->used_pages,
- (int) (ioc->used_pages * 100 / total_pages));
+ seq_printf(m, "IO PDIR entries : %ld free %ld used (%d%%)\n",
+ total_pages - ioc->used_pages, ioc->used_pages,
+ (int)(ioc->used_pages * 100 / total_pages));
min = max = ioc->avg_search[0];
for (i = 0; i < SBA_SEARCH_SAMPLE; i++) {
@@ -1813,79 +1827,46 @@ static int sba_proc_info(struct seq_file *m, void *p)
if (ioc->avg_search[i] < min) min = ioc->avg_search[i];
}
avg /= SBA_SEARCH_SAMPLE;
- len += seq_printf(m, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
- min, avg, max);
+ seq_printf(m, " Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
+ min, avg, max);
- len += seq_printf(m, "pci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n",
- ioc->msingle_calls, ioc->msingle_pages,
- (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls));
+ seq_printf(m, "pci_map_single(): %12ld calls %12ld pages (avg %d/1000)\n",
+ ioc->msingle_calls, ioc->msingle_pages,
+ (int)((ioc->msingle_pages * 1000)/ioc->msingle_calls));
/* KLUGE - unmap_sg calls unmap_single for each mapped page */
min = ioc->usingle_calls;
max = ioc->usingle_pages - ioc->usg_pages;
- len += seq_printf(m, "pci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n",
- min, max, (int) ((max * 1000)/min));
+ seq_printf(m, "pci_unmap_single: %12ld calls %12ld pages (avg %d/1000)\n",
+ min, max, (int)((max * 1000)/min));
- len += seq_printf(m, "pci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
- ioc->msg_calls, ioc->msg_pages,
- (int) ((ioc->msg_pages * 1000)/ioc->msg_calls));
+ seq_printf(m, "pci_map_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
+ ioc->msg_calls, ioc->msg_pages,
+ (int)((ioc->msg_pages * 1000)/ioc->msg_calls));
- len += seq_printf(m, "pci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
- ioc->usg_calls, ioc->usg_pages,
- (int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
+ seq_printf(m, "pci_unmap_sg() : %12ld calls %12ld pages (avg %d/1000)\n",
+ ioc->usg_calls, ioc->usg_pages,
+ (int)((ioc->usg_pages * 1000)/ioc->usg_calls));
#endif
return 0;
}
static int
-sba_proc_open(struct inode *i, struct file *f)
-{
- return single_open(f, &sba_proc_info, NULL);
-}
-
-static const struct file_operations sba_proc_fops = {
- .owner = THIS_MODULE,
- .open = sba_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int
sba_proc_bitmap_info(struct seq_file *m, void *p)
{
struct sba_device *sba_dev = sba_list;
struct ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */
- unsigned int *res_ptr = (unsigned int *)ioc->res_map;
- int i, len = 0;
- for (i = 0; i < (ioc->res_size/sizeof(unsigned int)); ++i, ++res_ptr) {
- if ((i & 7) == 0)
- len += seq_printf(m, "\n ");
- len += seq_printf(m, " %08x", *res_ptr);
- }
- len += seq_printf(m, "\n");
+ seq_hex_dump(m, " ", DUMP_PREFIX_NONE, 32, 4, ioc->res_map,
+ ioc->res_size, false);
+ seq_putc(m, '\n');
return 0;
}
-
-static int
-sba_proc_bitmap_open(struct inode *i, struct file *f)
-{
- return single_open(f, &sba_proc_bitmap_info, NULL);
-}
-
-static const struct file_operations sba_proc_bitmap_fops = {
- .owner = THIS_MODULE,
- .open = sba_proc_bitmap_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
#endif /* CONFIG_PROC_FS */
-static struct parisc_device_id sba_tbl[] = {
+static const struct parisc_device_id sba_tbl[] __initconst = {
{ HPHW_IOA, HVERSION_REV_ANY_ID, ASTRO_RUNWAY_PORT, 0xb },
{ HPHW_BCPORT, HVERSION_REV_ANY_ID, IKE_MERCED_PORT, 0xc },
{ HPHW_BCPORT, HVERSION_REV_ANY_ID, REO_MERCED_PORT, 0xc },
@@ -1896,7 +1877,7 @@ static struct parisc_device_id sba_tbl[] = {
static int sba_driver_callback(struct parisc_device *);
-static struct parisc_driver sba_driver = {
+static struct parisc_driver sba_driver __refdata = {
.name = MODULE_NAME,
.id_table = sba_tbl,
.probe = sba_driver_callback,
@@ -1907,16 +1888,14 @@ static struct parisc_driver sba_driver = {
** If so, initialize the chip and tell other partners in crime they
** have work to do.
*/
-static int sba_driver_callback(struct parisc_device *dev)
+static int __init sba_driver_callback(struct parisc_device *dev)
{
struct sba_device *sba_dev;
u32 func_class;
int i;
char *version;
- void __iomem *sba_addr = ioremap_nocache(dev->hpa.start, SBA_FUNC_SIZE);
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *root;
-#endif
+ void __iomem *sba_addr = ioremap(dev->hpa.start, SBA_FUNC_SIZE);
+ struct proc_dir_entry *root __maybe_unused;
sba_dump_ranges(sba_addr);
@@ -1982,23 +1961,23 @@ static int sba_driver_callback(struct parisc_device *dev)
hppa_dma_ops = &sba_ops;
-#ifdef CONFIG_PROC_FS
switch (dev->id.hversion) {
case PLUTO_MCKINLEY_PORT:
+ if (!proc_mckinley_root)
+ proc_mckinley_root = proc_mkdir("bus/mckinley", NULL);
root = proc_mckinley_root;
break;
case ASTRO_RUNWAY_PORT:
case IKE_MERCED_PORT:
default:
+ if (!proc_runway_root)
+ proc_runway_root = proc_mkdir("bus/runway", NULL);
root = proc_runway_root;
break;
}
- proc_create("sba_iommu", 0, root, &sba_proc_fops);
- proc_create("sba_iommu-bitmap", 0, root, &sba_proc_bitmap_fops);
-#endif
-
- parisc_has_iommu();
+ proc_create_single("sba_iommu", 0, root, sba_proc_info);
+ proc_create_single("sba_iommu-bitmap", 0, root, sba_proc_bitmap_info);
return 0;
}
@@ -2007,15 +1986,16 @@ static int sba_driver_callback(struct parisc_device *dev)
** This is the only routine which is NOT static.
** Must be called exactly once before pci_init().
*/
-void __init sba_init(void)
+static int __init sba_init(void)
{
- register_parisc_driver(&sba_driver);
+ return register_parisc_driver(&sba_driver);
}
+arch_initcall(sba_init);
/**
* sba_get_iommu - Assign the iommu pointer for the pci bus controller.
- * @dev: The parisc device.
+ * @pci_hba: The parisc device.
*
* Returns the appropriate IOMMU data for the given parisc PCI controller.
* This is cached and used later for PCI DMA Mapping.
@@ -2025,7 +2005,7 @@ void * sba_get_iommu(struct parisc_device *pci_hba)
struct parisc_device *sba_dev = parisc_parent(pci_hba);
struct sba_device *sba = dev_get_drvdata(&sba_dev->dev);
char t = sba_dev->id.hw_type;
- int iocnum = (pci_hba->hw_path >> 3); /* rope # */
+ int iocnum = (pci_hba->hw_path >> 3); /* IOC # */
WARN_ON((t != HPHW_IOA) && (t != HPHW_BCPORT));
@@ -2035,7 +2015,7 @@ void * sba_get_iommu(struct parisc_device *pci_hba)
/**
* sba_directed_lmmio - return first directed LMMIO range routed to rope
- * @pa_dev: The parisc device.
+ * @pci_hba: The parisc device.
* @r: resource PCI host controller wants start/end fields assigned.
*
* For the given parisc PCI controller, determine if any direct ranges
@@ -2077,7 +2057,7 @@ void sba_directed_lmmio(struct parisc_device *pci_hba, struct resource *r)
/**
* sba_distributed_lmmio - return portion of distributed LMMIO range
- * @pa_dev: The parisc device.
+ * @pci_hba: The parisc device.
* @r: resource PCI host controller wants start/end fields assigned.
*
* For the given parisc PCI controller, return portion of distributed LMMIO
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index a042d065a0c7..e973c6893203 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/* National Semiconductor NS87560UBD Super I/O controller used in
* HP [BCJ]x000 workstations.
*
@@ -14,11 +15,6 @@
* (C) Copyright 2005 Kyle McMartin <kyle@parisc-linux.org>
* (C) Copyright 2006 Helge Deller <deller@gmx.de>
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
* The initial version of this is by Martin Peterson. Alex deVries
* has spent a bit of time trying to coax it into working.
*
@@ -348,7 +344,7 @@ int superio_fixup_irq(struct pci_dev *pcidev)
BUG();
return -1;
}
- printk("superio_fixup_irq(%s) ven 0x%x dev 0x%x from %pf\n",
+ printk(KERN_DEBUG "superio_fixup_irq(%s) ven 0x%x dev 0x%x from %ps\n",
pci_name(pcidev),
pcidev->vendor, pcidev->device,
__builtin_return_address(0));
@@ -395,7 +391,8 @@ static void __init superio_serial_init(void)
serial_port.iotype = UPIO_PORT;
serial_port.type = PORT_16550A;
serial_port.uartclk = 115200*16;
- serial_port.fifosize = 16;
+ serial_port.flags = UPF_FIXED_PORT | UPF_FIXED_TYPE |
+ UPF_BOOT_AUTOCONF;
/* serial port #1 */
serial_port.iobase = sio_dev.sp1_base;
@@ -481,14 +478,14 @@ superio_probe(struct pci_dev *dev, const struct pci_device_id *id)
return -ENODEV;
}
-static const struct pci_device_id superio_tbl[] = {
+static const struct pci_device_id superio_tbl[] __initconst = {
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_LIO) },
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87560_USB) },
{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87415) },
{ 0, }
};
-static struct pci_driver superio_driver = {
+static struct pci_driver superio_driver __refdata = {
.name = SUPERIO,
.id_table = superio_tbl,
.probe = superio_probe,
diff --git a/drivers/parisc/wax.c b/drivers/parisc/wax.c
index da9d5ad1353c..834dbe9a767b 100644
--- a/drivers/parisc/wax.c
+++ b/drivers/parisc/wax.c
@@ -1,14 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* WAX Device Driver
*
* (c) Copyright 2000 The Puffin Group Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * by Helge Deller <deller@gmx.de>
+ * (c) 2000-2023 by Helge Deller <deller@gmx.de>
*/
#include <linux/errno.h>
@@ -72,7 +68,6 @@ static int __init wax_init_chip(struct parisc_device *dev)
{
struct gsc_asic *wax;
struct parisc_device *parent;
- struct gsc_irq gsc_irq;
int ret;
wax = kzalloc(sizeof(*wax), GFP_KERNEL);
@@ -89,7 +84,7 @@ static int __init wax_init_chip(struct parisc_device *dev)
wax_init_irq(wax);
/* the IRQ wax should use */
- dev->irq = gsc_claim_irq(&gsc_irq, WAX_GSC_IRQ);
+ dev->irq = gsc_claim_irq(&wax->gsc_irq, WAX_GSC_IRQ);
if (dev->irq < 0) {
printk(KERN_ERR "%s(): cannot get GSC irq\n",
__func__);
@@ -97,9 +92,9 @@ static int __init wax_init_chip(struct parisc_device *dev)
return -EBUSY;
}
- wax->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;
+ wax->eim = ((u32) wax->gsc_irq.txn_addr) | wax->gsc_irq.txn_data;
- ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "wax", wax);
+ ret = request_irq(wax->gsc_irq.irq, gsc_asic_intr, 0, "wax", wax);
if (ret < 0) {
kfree(wax);
return ret;
@@ -125,15 +120,21 @@ static int __init wax_init_chip(struct parisc_device *dev)
return ret;
}
-static struct parisc_device_id wax_tbl[] = {
- { HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008e },
+static const struct parisc_device_id wax_tbl[] __initconst = {
+ { HPHW_BA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008e },
{ 0, }
};
MODULE_DEVICE_TABLE(parisc, wax_tbl);
-struct parisc_driver wax_driver = {
+static struct parisc_driver wax_driver __refdata = {
.name = "wax",
.id_table = wax_tbl,
.probe = wax_init_chip,
};
+
+static int __init wax_init(void)
+{
+ return register_parisc_driver(&wax_driver);
+}
+arch_initcall(wax_init);