linux-mips.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/4] Use MFD framework for SGI IOC3 drivers
@ 2019-04-09 15:46 Thomas Bogendoerfer
  2019-04-09 15:46 ` [PATCH v2 1/4] MIPS: SGI-IP27: remove ioc3 ethernet init Thomas Bogendoerfer
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Thomas Bogendoerfer @ 2019-04-09 15:46 UTC (permalink / raw)
  To: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
	Lee Jones, David S. Miller, Alessandro Zummo, Alexandre Belloni,
	Greg Kroah-Hartman, Jiri Slaby, linux-mips, linux-kernel,
	linux-input, netdev, linux-rtc, linux-serial

SGI IOC3 ASIC includes support for ethernet, PS2 keyboard/mouse,
NIC (number in a can), GPIO and a byte  bus. By attaching a
SuperIO chip to it, it also supports serial lines and a parallel
port. The chip is used on a variety of SGI systems with different
configurations. This patchset moves code out of the network driver,
which doesn't belong there, into its new place a MFD driver and
specific platform drivers for the different subfunctions.

Change in v2:
 - fixed issue in ioc3kbd.c reported by Dmitry Torokhov
 - merged IP27 RTC removal and 8250 serial driver addition into
   main MFD patch to keep patches bisectable

Thomas Bogendoerfer (4):
  MIPS: SGI-IP27: remove ioc3 ethernet init
  mfd: ioc3: Add driver for SGI IOC3 chip
  MIPS: SGI-IP27: fix readb/writeb addressing
  Input: add IOC3 serio driver

 arch/mips/include/asm/mach-ip27/mangle-port.h |    2 +-
 arch/mips/include/asm/sn/ioc3.h               |  349 ++---
 arch/mips/sgi-ip27/ip27-console.c             |    5 +-
 arch/mips/sgi-ip27/ip27-init.c                |   13 -
 arch/mips/sgi-ip27/ip27-timer.c               |   20 -
 drivers/input/serio/Kconfig                   |   10 +
 drivers/input/serio/Makefile                  |    1 +
 drivers/input/serio/ioc3kbd.c                 |  158 +++
 drivers/mfd/Kconfig                           |   13 +
 drivers/mfd/Makefile                          |    1 +
 drivers/mfd/ioc3.c                            |  802 +++++++++++
 drivers/net/ethernet/sgi/Kconfig              |    4 +-
 drivers/net/ethernet/sgi/ioc3-eth.c           | 1867 +++++++++----------------
 drivers/rtc/rtc-m48t35.c                      |   11 +
 drivers/tty/serial/8250/8250_ioc3.c           |   98 ++
 drivers/tty/serial/8250/Kconfig               |   11 +
 drivers/tty/serial/8250/Makefile              |    1 +
 include/linux/platform_data/ioc3eth.h         |   15 +
 18 files changed, 1946 insertions(+), 1435 deletions(-)
 create mode 100644 drivers/input/serio/ioc3kbd.c
 create mode 100644 drivers/mfd/ioc3.c
 create mode 100644 drivers/tty/serial/8250/8250_ioc3.c
 create mode 100644 include/linux/platform_data/ioc3eth.h

-- 
2.13.7


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 1/4] MIPS: SGI-IP27: remove ioc3 ethernet init
  2019-04-09 15:46 [PATCH v2 0/4] Use MFD framework for SGI IOC3 drivers Thomas Bogendoerfer
@ 2019-04-09 15:46 ` Thomas Bogendoerfer
  2019-04-09 15:46 ` [PATCH v2 3/4] MIPS: SGI-IP27: fix readb/writeb addressing Thomas Bogendoerfer
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 11+ messages in thread
From: Thomas Bogendoerfer @ 2019-04-09 15:46 UTC (permalink / raw)
  To: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
	Lee Jones, David S. Miller, Alessandro Zummo, Alexandre Belloni,
	Greg Kroah-Hartman, Jiri Slaby, linux-mips, linux-kernel,
	linux-input, netdev, linux-rtc, linux-serial

Removed not needed disabling of ethernet interrupts in IP27 platform code.

Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
 arch/mips/sgi-ip27/ip27-init.c | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c
index 066b33f50bcc..59d5375c9021 100644
--- a/arch/mips/sgi-ip27/ip27-init.c
+++ b/arch/mips/sgi-ip27/ip27-init.c
@@ -130,17 +130,6 @@ cnodeid_t get_compact_nodeid(void)
 	return NASID_TO_COMPACT_NODEID(get_nasid());
 }
 
-static inline void ioc3_eth_init(void)
-{
-	struct ioc3 *ioc3;
-	nasid_t nid;
-
-	nid = get_nasid();
-	ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;
-
-	ioc3->eier = 0;
-}
-
 extern void ip27_reboot_setup(void);
 
 void __init plat_mem_setup(void)
@@ -182,8 +171,6 @@ void __init plat_mem_setup(void)
 		panic("Kernel compiled for N mode.");
 #endif
 
-	ioc3_eth_init();
-
 	ioport_resource.start = 0;
 	ioport_resource.end = ~0UL;
 	set_io_port_base(IO_BASE);
-- 
2.13.7


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 3/4] MIPS: SGI-IP27: fix readb/writeb addressing
  2019-04-09 15:46 [PATCH v2 0/4] Use MFD framework for SGI IOC3 drivers Thomas Bogendoerfer
  2019-04-09 15:46 ` [PATCH v2 1/4] MIPS: SGI-IP27: remove ioc3 ethernet init Thomas Bogendoerfer
@ 2019-04-09 15:46 ` Thomas Bogendoerfer
  2019-04-11 21:17   ` Alexandre Belloni
  2019-04-09 15:46 ` [PATCH v2 4/4] Input: add IOC3 serio driver Thomas Bogendoerfer
       [not found] ` <20190409154610.6735-3-tbogendoerfer@suse.de>
  3 siblings, 1 reply; 11+ messages in thread
From: Thomas Bogendoerfer @ 2019-04-09 15:46 UTC (permalink / raw)
  To: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
	Lee Jones, David S. Miller, Alessandro Zummo, Alexandre Belloni,
	Greg Kroah-Hartman, Jiri Slaby, linux-mips, linux-kernel,
	linux-input, netdev, linux-rtc, linux-serial

Our chosen byte swapping, which is what firmware already uses, is to
do readl/writel by normal lw/sw intructions (data invariance). This
also means we need to mangle addresses for u8 and u16 accesses. The
mangling for 16bit has been done aready, but 8bit one was missing.
Correcting this causes different addresses for accesses to the
SuperIO and local bus of the IOC3 chip. This is fixed by changing
byte order in ioc3 and m48rtc_rtc structs.

Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
 arch/mips/include/asm/mach-ip27/mangle-port.h |   2 +-
 arch/mips/include/asm/sn/ioc3.h               | 198 +++++++++++++-------------
 arch/mips/sgi-ip27/ip27-console.c             |   5 +-
 drivers/rtc/rtc-m48t35.c                      |  11 ++
 drivers/tty/serial/8250/8250_ioc3.c           |   4 +-
 5 files changed, 114 insertions(+), 106 deletions(-)

diff --git a/arch/mips/include/asm/mach-ip27/mangle-port.h b/arch/mips/include/asm/mach-ip27/mangle-port.h
index f6e4912ea062..7771ae0f3971 100644
--- a/arch/mips/include/asm/mach-ip27/mangle-port.h
+++ b/arch/mips/include/asm/mach-ip27/mangle-port.h
@@ -8,7 +8,7 @@
 #ifndef __ASM_MACH_IP27_MANGLE_PORT_H
 #define __ASM_MACH_IP27_MANGLE_PORT_H
 
-#define __swizzle_addr_b(port)	(port)
+#define __swizzle_addr_b(port)	((port) ^ 3)
 #define __swizzle_addr_w(port)	((port) ^ 2)
 #define __swizzle_addr_l(port)	(port)
 #define __swizzle_addr_q(port)	(port)
diff --git a/arch/mips/include/asm/sn/ioc3.h b/arch/mips/include/asm/sn/ioc3.h
index 69069f420930..059885d736de 100644
--- a/arch/mips/include/asm/sn/ioc3.h
+++ b/arch/mips/include/asm/sn/ioc3.h
@@ -10,35 +10,35 @@
 
 /* serial port register map */
 struct ioc3_serialregs {
-	uint32_t	sscr;
-	uint32_t	stpir;
-	uint32_t	stcir;
-	uint32_t	srpir;
-	uint32_t	srcir;
-	uint32_t	srtr;
-	uint32_t	shadow;
+	u32	sscr;
+	u32	stpir;
+	u32	stcir;
+	u32	srpir;
+	u32	srcir;
+	u32	srtr;
+	u32	shadow;
 };
 
 /* SUPERIO uart register map */
 struct ioc3_uartregs {
+	u8	iu_lcr;
 	union {
-		char	rbr;	/* read only, DLAB == 0 */
-		char	thr;	/* write only, DLAB == 0 */
-		char	dll;	/* DLAB == 1 */
-	} u1;
+		u8	iir;	/* read only */
+		u8	fcr;	/* write only */
+	};
 	union {
-		char	ier;	/* DLAB == 0 */
-		char	dlm;	/* DLAB == 1 */
-	} u2;
+		u8	ier;	/* DLAB == 0 */
+		u8	dlm;	/* DLAB == 1 */
+	};
 	union {
-		char	iir;	/* read only */
-		char	fcr;	/* write only */
-	} u3;
-	char	iu_lcr;
-	char	iu_mcr;
-	char	iu_lsr;
-	char	iu_msr;
-	char	iu_scr;
+		u8	rbr;	/* read only, DLAB == 0 */
+		u8	thr;	/* write only, DLAB == 0 */
+		u8	dll;	/* DLAB == 1 */
+	} u1;
+	u8	iu_scr;
+	u8	iu_msr;
+	u8	iu_lsr;
+	u8	iu_mcr;
 };
 
 #define iu_rbr u1.rbr
@@ -50,122 +50,122 @@ struct ioc3_uartregs {
 #define iu_fcr u3.fcr
 
 struct ioc3_sioregs {
-	char	fill[0x141];	/* starts at 0x141 */
+	u8	fill[0x141];	/* starts at 0x141 */
 
-	char	uartc;
-	char	kbdcg;
+	u8	kbdcg;
+	u8	uartc;
 
-	char	fill0[0x150 - 0x142 - 1];
+	u8	fill0[0x151 - 0x142 - 1];
 
-	char	pp_data;
-	char	pp_dsr;
-	char	pp_dcr;
+	u8	pp_dcr;
+	u8	pp_dsr;
+	u8	pp_data;
 
-	char	fill1[0x158 - 0x152 - 1];
+	u8	fill1[0x159 - 0x153 - 1];
 
-	char	pp_fifa;
-	char	pp_cfgb;
-	char	pp_ecr;
+	u8	pp_ecr;
+	u8	pp_cfgb;
+	u8	pp_fifa;
 
-	char	fill2[0x168 - 0x15a - 1];
+	u8	fill2[0x16a - 0x15b - 1];
 
-	char	rtcad;
-	char	rtcdat;
+	u8	rtcdat;
+	u8	rtcad;
 
-	char	fill3[0x170 - 0x169 - 1];
+	u8	fill3[0x170 - 0x16b - 1];
 
 	struct ioc3_uartregs	uartb;	/* 0x20170  */
 	struct ioc3_uartregs	uarta;	/* 0x20178  */
 };
 
 struct ioc3_ethregs {
-	uint32_t	emcr;		/* 0x000f0  */
-	uint32_t	eisr;		/* 0x000f4  */
-	uint32_t	eier;		/* 0x000f8  */
-	uint32_t	ercsr;		/* 0x000fc  */
-	uint32_t	erbr_h;		/* 0x00100  */
-	uint32_t	erbr_l;		/* 0x00104  */
-	uint32_t	erbar;		/* 0x00108  */
-	uint32_t	ercir;		/* 0x0010c  */
-	uint32_t	erpir;		/* 0x00110  */
-	uint32_t	ertr;		/* 0x00114  */
-	uint32_t	etcsr;		/* 0x00118  */
-	uint32_t	ersr;		/* 0x0011c  */
-	uint32_t	etcdc;		/* 0x00120  */
-	uint32_t	ebir;		/* 0x00124  */
-	uint32_t	etbr_h;		/* 0x00128  */
-	uint32_t	etbr_l;		/* 0x0012c  */
-	uint32_t	etcir;		/* 0x00130  */
-	uint32_t	etpir;		/* 0x00134  */
-	uint32_t	emar_h;		/* 0x00138  */
-	uint32_t	emar_l;		/* 0x0013c  */
-	uint32_t	ehar_h;		/* 0x00140  */
-	uint32_t	ehar_l;		/* 0x00144  */
-	uint32_t	micr;		/* 0x00148  */
-	uint32_t	midr_r;		/* 0x0014c  */
-	uint32_t	midr_w;		/* 0x00150  */
+	u32	emcr;		/* 0x000f0  */
+	u32	eisr;		/* 0x000f4  */
+	u32	eier;		/* 0x000f8  */
+	u32	ercsr;		/* 0x000fc  */
+	u32	erbr_h;		/* 0x00100  */
+	u32	erbr_l;		/* 0x00104  */
+	u32	erbar;		/* 0x00108  */
+	u32	ercir;		/* 0x0010c  */
+	u32	erpir;		/* 0x00110  */
+	u32	ertr;		/* 0x00114  */
+	u32	etcsr;		/* 0x00118  */
+	u32	ersr;		/* 0x0011c  */
+	u32	etcdc;		/* 0x00120  */
+	u32	ebir;		/* 0x00124  */
+	u32	etbr_h;		/* 0x00128  */
+	u32	etbr_l;		/* 0x0012c  */
+	u32	etcir;		/* 0x00130  */
+	u32	etpir;		/* 0x00134  */
+	u32	emar_h;		/* 0x00138  */
+	u32	emar_l;		/* 0x0013c  */
+	u32	ehar_h;		/* 0x00140  */
+	u32	ehar_l;		/* 0x00144  */
+	u32	micr;		/* 0x00148  */
+	u32	midr_r;		/* 0x0014c  */
+	u32	midr_w;		/* 0x00150  */
 };
 
 struct ioc3_serioregs {
-	uint32_t	km_csr;		/* 0x0009c  */
-	uint32_t	k_rd;		/* 0x000a0  */
-	uint32_t	m_rd;		/* 0x000a4  */
-	uint32_t	k_wd;		/* 0x000a8  */
-	uint32_t	m_wd;		/* 0x000ac  */
+	u32	km_csr;		/* 0x0009c  */
+	u32	k_rd;		/* 0x000a0  */
+	u32	m_rd;		/* 0x000a4  */
+	u32	k_wd;		/* 0x000a8  */
+	u32	m_wd;		/* 0x000ac  */
 };
 
 /* Register layout of IOC3 in configuration space.  */
 struct ioc3 {
 	/* PCI Config Space registers  */
-	uint32_t	pci_id;		/* 0x00000  */
-	uint32_t	pci_scr;	/* 0x00004  */
-	uint32_t	pci_rev;	/* 0x00008  */
-	uint32_t	pci_lat;	/* 0x0000c  */
-	uint32_t	pci_addr;	/* 0x00010  */
-	uint32_t	pci_err_addr_l;	/* 0x00014  */
-	uint32_t	pci_err_addr_h;	/* 0x00018  */
-
-	uint32_t	sio_ir;		/* 0x0001c  */
-	uint32_t	sio_ies;	/* 0x00020  */
-	uint32_t	sio_iec;	/* 0x00024  */
-	uint32_t	sio_cr;		/* 0x00028  */
-	uint32_t	int_out;	/* 0x0002c  */
-	uint32_t	mcr;		/* 0x00030  */
+	u32	pci_id;		/* 0x00000  */
+	u32	pci_scr;	/* 0x00004  */
+	u32	pci_rev;	/* 0x00008  */
+	u32	pci_lat;	/* 0x0000c  */
+	u32	pci_addr;	/* 0x00010  */
+	u32	pci_err_addr_l;	/* 0x00014  */
+	u32	pci_err_addr_h;	/* 0x00018  */
+
+	u32	sio_ir;		/* 0x0001c  */
+	u32	sio_ies;	/* 0x00020  */
+	u32	sio_iec;	/* 0x00024  */
+	u32	sio_cr;		/* 0x00028  */
+	u32	int_out;	/* 0x0002c  */
+	u32	mcr;		/* 0x00030  */
 
 	/* General Purpose I/O registers  */
-	uint32_t	gpcr_s;		/* 0x00034  */
-	uint32_t	gpcr_c;		/* 0x00038  */
-	uint32_t	gpdr;		/* 0x0003c  */
-	uint32_t	gppr[16];	/* 0x00040  */
+	u32	gpcr_s;		/* 0x00034  */
+	u32	gpcr_c;		/* 0x00038  */
+	u32	gpdr;		/* 0x0003c  */
+	u32	gppr[16];	/* 0x00040  */
 
 	/* Parallel Port Registers  */
-	uint32_t	ppbr_h_a;	/* 0x00080  */
-	uint32_t	ppbr_l_a;	/* 0x00084  */
-	uint32_t	ppcr_a;		/* 0x00088  */
-	uint32_t	ppcr;		/* 0x0008c  */
-	uint32_t	ppbr_h_b;	/* 0x00090  */
-	uint32_t	ppbr_l_b;	/* 0x00094  */
-	uint32_t	ppcr_b;		/* 0x00098  */
+	u32	ppbr_h_a;	/* 0x00080  */
+	u32	ppbr_l_a;	/* 0x00084  */
+	u32	ppcr_a;		/* 0x00088  */
+	u32	ppcr;		/* 0x0008c  */
+	u32	ppbr_h_b;	/* 0x00090  */
+	u32	ppbr_l_b;	/* 0x00094  */
+	u32	ppcr_b;		/* 0x00098  */
 
 	/* Keyboard and Mouse Registers	 */
 	struct ioc3_serioregs	serio;
 
 	/* Serial Port Registers  */
-	uint32_t	sbbr_h;		/* 0x000b0  */
-	uint32_t	sbbr_l;		/* 0x000b4  */
+	u32	sbbr_h;		/* 0x000b0  */
+	u32	sbbr_l;		/* 0x000b4  */
 	struct ioc3_serialregs	port_a;
 	struct ioc3_serialregs	port_b;
 
 	/* Ethernet Registers */
 	struct ioc3_ethregs	eth;
-	uint32_t	pad1[(0x20000 - 0x00154) / 4];
+	u32	pad1[(0x20000 - 0x00154) / 4];
 
 	/* SuperIO Registers  XXX */
 	struct ioc3_sioregs	sregs;	/* 0x20000 */
-	uint32_t	pad2[(0x40000 - 0x20180) / 4];
+	u32	pad2[(0x40000 - 0x20180) / 4];
 
 	/* SSRAM Diagnostic Access */
-	uint32_t	ssram[(0x80000 - 0x40000) / 4];
+	u32	ssram[(0x80000 - 0x40000) / 4];
 
 	/* Bytebus device offsets
 	   0x80000 -   Access to the generic devices selected with   DEV0
@@ -598,8 +598,4 @@ struct ioc3_etxd {
 
 #define MIDR_DATA_MASK		0x0000ffff
 
-#if defined(CONFIG_SGI_IP27) || defined(CONFIG_SGI_IP30)
-extern int bridge_alloc_irq(struct pci_dev *dev);
-#endif
-
 #endif /* MIPS_SN_IOC3_H */
diff --git a/arch/mips/sgi-ip27/ip27-console.c b/arch/mips/sgi-ip27/ip27-console.c
index 6bdb48d41276..5886bee89d06 100644
--- a/arch/mips/sgi-ip27/ip27-console.c
+++ b/arch/mips/sgi-ip27/ip27-console.c
@@ -35,6 +35,7 @@ void prom_putchar(char c)
 {
 	struct ioc3_uartregs *uart = console_uart();
 
-	while ((uart->iu_lsr & 0x20) == 0);
-	uart->iu_thr = c;
+	while ((readb(&uart->iu_lsr) & 0x20) == 0)
+		;
+	writeb(c, &uart->iu_thr);
 }
diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c
index 0cf6507de3c7..05f0d91366af 100644
--- a/drivers/rtc/rtc-m48t35.c
+++ b/drivers/rtc/rtc-m48t35.c
@@ -24,6 +24,16 @@
 
 struct m48t35_rtc {
 	u8	pad[0x7ff8];    /* starts at 0x7ff8 */
+#ifdef CONFIG_SGI_IP27
+	u8	hour;
+	u8	min;
+	u8	sec;
+	u8	control;
+	u8	year;
+	u8	month;
+	u8	date;
+	u8	day;
+#else
 	u8	control;
 	u8	sec;
 	u8	min;
@@ -32,6 +42,7 @@ struct m48t35_rtc {
 	u8	date;
 	u8	month;
 	u8	year;
+#endif
 };
 
 #define M48T35_RTC_SET		0x80
diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c
index 2be6ed2967e0..4c405f1b9c67 100644
--- a/drivers/tty/serial/8250/8250_ioc3.c
+++ b/drivers/tty/serial/8250/8250_ioc3.c
@@ -23,12 +23,12 @@ struct ioc3_8250_data {
 
 static unsigned int ioc3_serial_in(struct uart_port *p, int offset)
 {
-	return readb(p->membase + offset);
+	return readb(p->membase + (offset ^ 3));
 }
 
 static void ioc3_serial_out(struct uart_port *p, int offset, int value)
 {
-	writeb(value, p->membase + offset);
+	writeb(value, p->membase + (offset ^ 3));
 }
 
 static int serial8250_ioc3_probe(struct platform_device *pdev)
-- 
2.13.7


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 4/4] Input: add IOC3 serio driver
  2019-04-09 15:46 [PATCH v2 0/4] Use MFD framework for SGI IOC3 drivers Thomas Bogendoerfer
  2019-04-09 15:46 ` [PATCH v2 1/4] MIPS: SGI-IP27: remove ioc3 ethernet init Thomas Bogendoerfer
  2019-04-09 15:46 ` [PATCH v2 3/4] MIPS: SGI-IP27: fix readb/writeb addressing Thomas Bogendoerfer
@ 2019-04-09 15:46 ` Thomas Bogendoerfer
       [not found] ` <20190409154610.6735-3-tbogendoerfer@suse.de>
  3 siblings, 0 replies; 11+ messages in thread
From: Thomas Bogendoerfer @ 2019-04-09 15:46 UTC (permalink / raw)
  To: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
	Lee Jones, David S. Miller, Alessandro Zummo, Alexandre Belloni,
	Greg Kroah-Hartman, Jiri Slaby, linux-mips, linux-kernel,
	linux-input, netdev, linux-rtc, linux-serial

This patch adds a platform driver for supporting keyboard and mouse
interface of SGI IOC3 chips.

Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
 drivers/input/serio/Kconfig   |  10 +++
 drivers/input/serio/Makefile  |   1 +
 drivers/input/serio/ioc3kbd.c | 158 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 169 insertions(+)
 create mode 100644 drivers/input/serio/ioc3kbd.c

diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index c9c7224d5ae0..2db47c9ff9c2 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -164,6 +164,16 @@ config SERIO_MACEPS2
 	  To compile this driver as a module, choose M here: the
 	  module will be called maceps2.
 
+config SERIO_SGI_IOC3
+	tristate "SGI IOC3 PS/2 controller"
+	depends on SGI_MFD_IOC3
+	help
+	  Say Y here if you have an SGI Onyx2, SGI Octane or IOC3 PCI card
+	  and you want to attach and use a keyboard, mouse, or both.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ioc3kbd.
+
 config SERIO_LIBPS2
 	tristate "PS/2 driver library"
 	depends on SERIO_I8042 || SERIO_I8042=n
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 67950a5ccb3f..6d97bad7b844 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_HIL_MLC)		+= hp_sdc_mlc.o hil_mlc.o
 obj-$(CONFIG_SERIO_PCIPS2)	+= pcips2.o
 obj-$(CONFIG_SERIO_PS2MULT)	+= ps2mult.o
 obj-$(CONFIG_SERIO_MACEPS2)	+= maceps2.o
+obj-$(CONFIG_SERIO_SGI_IOC3)	+= ioc3kbd.o
 obj-$(CONFIG_SERIO_LIBPS2)	+= libps2.o
 obj-$(CONFIG_SERIO_RAW)		+= serio_raw.o
 obj-$(CONFIG_SERIO_AMS_DELTA)	+= ams_delta_serio.o
diff --git a/drivers/input/serio/ioc3kbd.c b/drivers/input/serio/ioc3kbd.c
new file mode 100644
index 000000000000..26fcf57465d6
--- /dev/null
+++ b/drivers/input/serio/ioc3kbd.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * SGI IOC3 PS/2 controller driver for linux
+ *
+ * Copyright (C) 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de>
+ *
+ * Based on code Copyright (C) 2005 Stanislaw Skowronek <skylark@unaligned.org>
+ *               Copyright (C) 2009 Johannes Dickgreber <tanzy@gmx.de>
+ */
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/serio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/sn/ioc3.h>
+
+struct ioc3kbd_data {
+	struct ioc3_serioregs __iomem *regs;
+	struct serio *kbd, *aux;
+};
+
+static int ioc3kbd_write(struct serio *dev, u8 val)
+{
+	struct ioc3kbd_data *d = dev->port_data;
+	unsigned long timeout = 0;
+	u32 mask;
+
+	mask = (dev == d->aux) ? KM_CSR_M_WRT_PEND : KM_CSR_K_WRT_PEND;
+	while ((readl(&d->regs->km_csr) & mask) && (timeout < 1000)) {
+		udelay(100);
+		timeout++;
+	}
+
+	if (timeout >= 1000)
+		return -1;
+
+	writel(val, dev == d->aux ?  &d->regs->m_wd : &d->regs->k_wd);
+
+	return 0;
+}
+
+static irqreturn_t ioc3kbd_intr(int itq, void *dev_id)
+{
+	struct ioc3kbd_data *d = dev_id;
+	u32 data_k, data_m;
+
+	data_k = readl(&d->regs->k_rd);
+	data_m = readl(&d->regs->m_rd);
+
+	if (data_k & KM_RD_VALID_0)
+		serio_interrupt(d->kbd,
+		(data_k >> KM_RD_DATA_0_SHIFT) & 0xff, 0);
+	if (data_k & KM_RD_VALID_1)
+		serio_interrupt(d->kbd,
+		(data_k >> KM_RD_DATA_1_SHIFT) & 0xff, 0);
+	if (data_k & KM_RD_VALID_2)
+		serio_interrupt(d->kbd,
+		(data_k >> KM_RD_DATA_2_SHIFT) & 0xff, 0);
+	if (data_m & KM_RD_VALID_0)
+		serio_interrupt(d->aux,
+		(data_m >> KM_RD_DATA_0_SHIFT) & 0xff, 0);
+	if (data_m & KM_RD_VALID_1)
+		serio_interrupt(d->aux,
+		(data_m >> KM_RD_DATA_1_SHIFT) & 0xff, 0);
+	if (data_m & KM_RD_VALID_2)
+		serio_interrupt(d->aux,
+		(data_m >> KM_RD_DATA_2_SHIFT) & 0xff, 0);
+
+	return 0;
+}
+
+static int ioc3kbd_probe(struct platform_device *pdev)
+{
+	struct ioc3_serioregs __iomem *regs;
+	struct device *dev = &pdev->dev;
+	struct ioc3kbd_data *d;
+	struct serio *sk, *sa;
+	struct resource *mem;
+	int irq, ret;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	regs = devm_ioremap_resource(&pdev->dev, mem);
+	if (IS_ERR(regs))
+		return PTR_ERR(regs);
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -ENXIO;
+
+	d = devm_kzalloc(&pdev->dev, sizeof(struct ioc3kbd_data), GFP_KERNEL);
+	if (!d)
+		return -ENOMEM;
+
+	ret = devm_request_irq(&pdev->dev, irq, ioc3kbd_intr, IRQF_SHARED,
+			       "ioc3-kbd", d);
+	if (ret) {
+		dev_err(&pdev->dev, "could not request IRQ %d\n", irq);
+		return ret;
+	}
+
+	sk = kzalloc(sizeof(struct serio), GFP_KERNEL);
+	if (!sk)
+		return -ENOMEM;
+
+	sa = kzalloc(sizeof(struct serio), GFP_KERNEL);
+	if (!sa) {
+		kfree(sk);
+		return -ENOMEM;
+	}
+
+	sk->id.type = SERIO_8042;
+	sk->write = ioc3kbd_write;
+	snprintf(sk->name, sizeof(sk->name), "IOC3 keyboard %d", pdev->id);
+	snprintf(sk->phys, sizeof(sk->phys), "ioc3/serio%dkbd", pdev->id);
+	sk->port_data = d;
+	sk->dev.parent = &pdev->dev;
+
+	sa->id.type = SERIO_8042;
+	sa->write = ioc3kbd_write;
+	snprintf(sa->name, sizeof(sa->name), "IOC3 auxiliary %d", pdev->id);
+	snprintf(sa->phys, sizeof(sa->phys), "ioc3/serio%daux", pdev->id);
+	sa->port_data = d;
+	sa->dev.parent = dev;
+
+	d->regs = regs;
+	d->kbd = sk;
+	d->aux = sa;
+
+	platform_set_drvdata(pdev, d);
+	serio_register_port(d->kbd);
+	serio_register_port(d->aux);
+	return 0;
+}
+
+static int ioc3kbd_remove(struct platform_device *pdev)
+{
+	struct ioc3kbd_data *d = platform_get_drvdata(pdev);
+
+	serio_unregister_port(d->kbd);
+	serio_unregister_port(d->aux);
+	return 0;
+}
+
+static struct platform_driver ioc3kbd_driver = {
+	.probe          = ioc3kbd_probe,
+	.remove         = ioc3kbd_remove,
+	.driver = {
+		.name = "ioc3-kbd",
+	},
+};
+module_platform_driver(ioc3kbd_driver);
+
+MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>");
+MODULE_DESCRIPTION("SGI IOC3 serio driver");
+MODULE_LICENSE("GPL");
-- 
2.13.7


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 3/4] MIPS: SGI-IP27: fix readb/writeb addressing
  2019-04-09 15:46 ` [PATCH v2 3/4] MIPS: SGI-IP27: fix readb/writeb addressing Thomas Bogendoerfer
@ 2019-04-11 21:17   ` Alexandre Belloni
  0 siblings, 0 replies; 11+ messages in thread
From: Alexandre Belloni @ 2019-04-11 21:17 UTC (permalink / raw)
  To: Thomas Bogendoerfer
  Cc: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
	Lee Jones, David S. Miller, Alessandro Zummo, Greg Kroah-Hartman,
	Jiri Slaby, linux-mips, linux-kernel, linux-input, netdev,
	linux-rtc, linux-serial

On 09/04/2019 17:46:07+0200, Thomas Bogendoerfer wrote:
> Our chosen byte swapping, which is what firmware already uses, is to
> do readl/writel by normal lw/sw intructions (data invariance). This
> also means we need to mangle addresses for u8 and u16 accesses. The
> mangling for 16bit has been done aready, but 8bit one was missing.
> Correcting this causes different addresses for accesses to the
> SuperIO and local bus of the IOC3 chip. This is fixed by changing
> byte order in ioc3 and m48rtc_rtc structs.
> 
> Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>

Considering this is probably the only platform to have that RTC and that
is probably not worth having a better fix for a platform this old:

Acked-by: Alexandre Belloni <alexandre.belloni@bootlin.com>

> ---
>  arch/mips/include/asm/mach-ip27/mangle-port.h |   2 +-
>  arch/mips/include/asm/sn/ioc3.h               | 198 +++++++++++++-------------
>  arch/mips/sgi-ip27/ip27-console.c             |   5 +-
>  drivers/rtc/rtc-m48t35.c                      |  11 ++
>  drivers/tty/serial/8250/8250_ioc3.c           |   4 +-
>  5 files changed, 114 insertions(+), 106 deletions(-)
> 
> diff --git a/arch/mips/include/asm/mach-ip27/mangle-port.h b/arch/mips/include/asm/mach-ip27/mangle-port.h
> index f6e4912ea062..7771ae0f3971 100644
> --- a/arch/mips/include/asm/mach-ip27/mangle-port.h
> +++ b/arch/mips/include/asm/mach-ip27/mangle-port.h
> @@ -8,7 +8,7 @@
>  #ifndef __ASM_MACH_IP27_MANGLE_PORT_H
>  #define __ASM_MACH_IP27_MANGLE_PORT_H
>  
> -#define __swizzle_addr_b(port)	(port)
> +#define __swizzle_addr_b(port)	((port) ^ 3)
>  #define __swizzle_addr_w(port)	((port) ^ 2)
>  #define __swizzle_addr_l(port)	(port)
>  #define __swizzle_addr_q(port)	(port)
> diff --git a/arch/mips/include/asm/sn/ioc3.h b/arch/mips/include/asm/sn/ioc3.h
> index 69069f420930..059885d736de 100644
> --- a/arch/mips/include/asm/sn/ioc3.h
> +++ b/arch/mips/include/asm/sn/ioc3.h
> @@ -10,35 +10,35 @@
>  
>  /* serial port register map */
>  struct ioc3_serialregs {
> -	uint32_t	sscr;
> -	uint32_t	stpir;
> -	uint32_t	stcir;
> -	uint32_t	srpir;
> -	uint32_t	srcir;
> -	uint32_t	srtr;
> -	uint32_t	shadow;
> +	u32	sscr;
> +	u32	stpir;
> +	u32	stcir;
> +	u32	srpir;
> +	u32	srcir;
> +	u32	srtr;
> +	u32	shadow;
>  };
>  
>  /* SUPERIO uart register map */
>  struct ioc3_uartregs {
> +	u8	iu_lcr;
>  	union {
> -		char	rbr;	/* read only, DLAB == 0 */
> -		char	thr;	/* write only, DLAB == 0 */
> -		char	dll;	/* DLAB == 1 */
> -	} u1;
> +		u8	iir;	/* read only */
> +		u8	fcr;	/* write only */
> +	};
>  	union {
> -		char	ier;	/* DLAB == 0 */
> -		char	dlm;	/* DLAB == 1 */
> -	} u2;
> +		u8	ier;	/* DLAB == 0 */
> +		u8	dlm;	/* DLAB == 1 */
> +	};
>  	union {
> -		char	iir;	/* read only */
> -		char	fcr;	/* write only */
> -	} u3;
> -	char	iu_lcr;
> -	char	iu_mcr;
> -	char	iu_lsr;
> -	char	iu_msr;
> -	char	iu_scr;
> +		u8	rbr;	/* read only, DLAB == 0 */
> +		u8	thr;	/* write only, DLAB == 0 */
> +		u8	dll;	/* DLAB == 1 */
> +	} u1;
> +	u8	iu_scr;
> +	u8	iu_msr;
> +	u8	iu_lsr;
> +	u8	iu_mcr;
>  };
>  
>  #define iu_rbr u1.rbr
> @@ -50,122 +50,122 @@ struct ioc3_uartregs {
>  #define iu_fcr u3.fcr
>  
>  struct ioc3_sioregs {
> -	char	fill[0x141];	/* starts at 0x141 */
> +	u8	fill[0x141];	/* starts at 0x141 */
>  
> -	char	uartc;
> -	char	kbdcg;
> +	u8	kbdcg;
> +	u8	uartc;
>  
> -	char	fill0[0x150 - 0x142 - 1];
> +	u8	fill0[0x151 - 0x142 - 1];
>  
> -	char	pp_data;
> -	char	pp_dsr;
> -	char	pp_dcr;
> +	u8	pp_dcr;
> +	u8	pp_dsr;
> +	u8	pp_data;
>  
> -	char	fill1[0x158 - 0x152 - 1];
> +	u8	fill1[0x159 - 0x153 - 1];
>  
> -	char	pp_fifa;
> -	char	pp_cfgb;
> -	char	pp_ecr;
> +	u8	pp_ecr;
> +	u8	pp_cfgb;
> +	u8	pp_fifa;
>  
> -	char	fill2[0x168 - 0x15a - 1];
> +	u8	fill2[0x16a - 0x15b - 1];
>  
> -	char	rtcad;
> -	char	rtcdat;
> +	u8	rtcdat;
> +	u8	rtcad;
>  
> -	char	fill3[0x170 - 0x169 - 1];
> +	u8	fill3[0x170 - 0x16b - 1];
>  
>  	struct ioc3_uartregs	uartb;	/* 0x20170  */
>  	struct ioc3_uartregs	uarta;	/* 0x20178  */
>  };
>  
>  struct ioc3_ethregs {
> -	uint32_t	emcr;		/* 0x000f0  */
> -	uint32_t	eisr;		/* 0x000f4  */
> -	uint32_t	eier;		/* 0x000f8  */
> -	uint32_t	ercsr;		/* 0x000fc  */
> -	uint32_t	erbr_h;		/* 0x00100  */
> -	uint32_t	erbr_l;		/* 0x00104  */
> -	uint32_t	erbar;		/* 0x00108  */
> -	uint32_t	ercir;		/* 0x0010c  */
> -	uint32_t	erpir;		/* 0x00110  */
> -	uint32_t	ertr;		/* 0x00114  */
> -	uint32_t	etcsr;		/* 0x00118  */
> -	uint32_t	ersr;		/* 0x0011c  */
> -	uint32_t	etcdc;		/* 0x00120  */
> -	uint32_t	ebir;		/* 0x00124  */
> -	uint32_t	etbr_h;		/* 0x00128  */
> -	uint32_t	etbr_l;		/* 0x0012c  */
> -	uint32_t	etcir;		/* 0x00130  */
> -	uint32_t	etpir;		/* 0x00134  */
> -	uint32_t	emar_h;		/* 0x00138  */
> -	uint32_t	emar_l;		/* 0x0013c  */
> -	uint32_t	ehar_h;		/* 0x00140  */
> -	uint32_t	ehar_l;		/* 0x00144  */
> -	uint32_t	micr;		/* 0x00148  */
> -	uint32_t	midr_r;		/* 0x0014c  */
> -	uint32_t	midr_w;		/* 0x00150  */
> +	u32	emcr;		/* 0x000f0  */
> +	u32	eisr;		/* 0x000f4  */
> +	u32	eier;		/* 0x000f8  */
> +	u32	ercsr;		/* 0x000fc  */
> +	u32	erbr_h;		/* 0x00100  */
> +	u32	erbr_l;		/* 0x00104  */
> +	u32	erbar;		/* 0x00108  */
> +	u32	ercir;		/* 0x0010c  */
> +	u32	erpir;		/* 0x00110  */
> +	u32	ertr;		/* 0x00114  */
> +	u32	etcsr;		/* 0x00118  */
> +	u32	ersr;		/* 0x0011c  */
> +	u32	etcdc;		/* 0x00120  */
> +	u32	ebir;		/* 0x00124  */
> +	u32	etbr_h;		/* 0x00128  */
> +	u32	etbr_l;		/* 0x0012c  */
> +	u32	etcir;		/* 0x00130  */
> +	u32	etpir;		/* 0x00134  */
> +	u32	emar_h;		/* 0x00138  */
> +	u32	emar_l;		/* 0x0013c  */
> +	u32	ehar_h;		/* 0x00140  */
> +	u32	ehar_l;		/* 0x00144  */
> +	u32	micr;		/* 0x00148  */
> +	u32	midr_r;		/* 0x0014c  */
> +	u32	midr_w;		/* 0x00150  */
>  };
>  
>  struct ioc3_serioregs {
> -	uint32_t	km_csr;		/* 0x0009c  */
> -	uint32_t	k_rd;		/* 0x000a0  */
> -	uint32_t	m_rd;		/* 0x000a4  */
> -	uint32_t	k_wd;		/* 0x000a8  */
> -	uint32_t	m_wd;		/* 0x000ac  */
> +	u32	km_csr;		/* 0x0009c  */
> +	u32	k_rd;		/* 0x000a0  */
> +	u32	m_rd;		/* 0x000a4  */
> +	u32	k_wd;		/* 0x000a8  */
> +	u32	m_wd;		/* 0x000ac  */
>  };
>  
>  /* Register layout of IOC3 in configuration space.  */
>  struct ioc3 {
>  	/* PCI Config Space registers  */
> -	uint32_t	pci_id;		/* 0x00000  */
> -	uint32_t	pci_scr;	/* 0x00004  */
> -	uint32_t	pci_rev;	/* 0x00008  */
> -	uint32_t	pci_lat;	/* 0x0000c  */
> -	uint32_t	pci_addr;	/* 0x00010  */
> -	uint32_t	pci_err_addr_l;	/* 0x00014  */
> -	uint32_t	pci_err_addr_h;	/* 0x00018  */
> -
> -	uint32_t	sio_ir;		/* 0x0001c  */
> -	uint32_t	sio_ies;	/* 0x00020  */
> -	uint32_t	sio_iec;	/* 0x00024  */
> -	uint32_t	sio_cr;		/* 0x00028  */
> -	uint32_t	int_out;	/* 0x0002c  */
> -	uint32_t	mcr;		/* 0x00030  */
> +	u32	pci_id;		/* 0x00000  */
> +	u32	pci_scr;	/* 0x00004  */
> +	u32	pci_rev;	/* 0x00008  */
> +	u32	pci_lat;	/* 0x0000c  */
> +	u32	pci_addr;	/* 0x00010  */
> +	u32	pci_err_addr_l;	/* 0x00014  */
> +	u32	pci_err_addr_h;	/* 0x00018  */
> +
> +	u32	sio_ir;		/* 0x0001c  */
> +	u32	sio_ies;	/* 0x00020  */
> +	u32	sio_iec;	/* 0x00024  */
> +	u32	sio_cr;		/* 0x00028  */
> +	u32	int_out;	/* 0x0002c  */
> +	u32	mcr;		/* 0x00030  */
>  
>  	/* General Purpose I/O registers  */
> -	uint32_t	gpcr_s;		/* 0x00034  */
> -	uint32_t	gpcr_c;		/* 0x00038  */
> -	uint32_t	gpdr;		/* 0x0003c  */
> -	uint32_t	gppr[16];	/* 0x00040  */
> +	u32	gpcr_s;		/* 0x00034  */
> +	u32	gpcr_c;		/* 0x00038  */
> +	u32	gpdr;		/* 0x0003c  */
> +	u32	gppr[16];	/* 0x00040  */
>  
>  	/* Parallel Port Registers  */
> -	uint32_t	ppbr_h_a;	/* 0x00080  */
> -	uint32_t	ppbr_l_a;	/* 0x00084  */
> -	uint32_t	ppcr_a;		/* 0x00088  */
> -	uint32_t	ppcr;		/* 0x0008c  */
> -	uint32_t	ppbr_h_b;	/* 0x00090  */
> -	uint32_t	ppbr_l_b;	/* 0x00094  */
> -	uint32_t	ppcr_b;		/* 0x00098  */
> +	u32	ppbr_h_a;	/* 0x00080  */
> +	u32	ppbr_l_a;	/* 0x00084  */
> +	u32	ppcr_a;		/* 0x00088  */
> +	u32	ppcr;		/* 0x0008c  */
> +	u32	ppbr_h_b;	/* 0x00090  */
> +	u32	ppbr_l_b;	/* 0x00094  */
> +	u32	ppcr_b;		/* 0x00098  */
>  
>  	/* Keyboard and Mouse Registers	 */
>  	struct ioc3_serioregs	serio;
>  
>  	/* Serial Port Registers  */
> -	uint32_t	sbbr_h;		/* 0x000b0  */
> -	uint32_t	sbbr_l;		/* 0x000b4  */
> +	u32	sbbr_h;		/* 0x000b0  */
> +	u32	sbbr_l;		/* 0x000b4  */
>  	struct ioc3_serialregs	port_a;
>  	struct ioc3_serialregs	port_b;
>  
>  	/* Ethernet Registers */
>  	struct ioc3_ethregs	eth;
> -	uint32_t	pad1[(0x20000 - 0x00154) / 4];
> +	u32	pad1[(0x20000 - 0x00154) / 4];
>  
>  	/* SuperIO Registers  XXX */
>  	struct ioc3_sioregs	sregs;	/* 0x20000 */
> -	uint32_t	pad2[(0x40000 - 0x20180) / 4];
> +	u32	pad2[(0x40000 - 0x20180) / 4];
>  
>  	/* SSRAM Diagnostic Access */
> -	uint32_t	ssram[(0x80000 - 0x40000) / 4];
> +	u32	ssram[(0x80000 - 0x40000) / 4];
>  
>  	/* Bytebus device offsets
>  	   0x80000 -   Access to the generic devices selected with   DEV0
> @@ -598,8 +598,4 @@ struct ioc3_etxd {
>  
>  #define MIDR_DATA_MASK		0x0000ffff
>  
> -#if defined(CONFIG_SGI_IP27) || defined(CONFIG_SGI_IP30)
> -extern int bridge_alloc_irq(struct pci_dev *dev);
> -#endif
> -
>  #endif /* MIPS_SN_IOC3_H */
> diff --git a/arch/mips/sgi-ip27/ip27-console.c b/arch/mips/sgi-ip27/ip27-console.c
> index 6bdb48d41276..5886bee89d06 100644
> --- a/arch/mips/sgi-ip27/ip27-console.c
> +++ b/arch/mips/sgi-ip27/ip27-console.c
> @@ -35,6 +35,7 @@ void prom_putchar(char c)
>  {
>  	struct ioc3_uartregs *uart = console_uart();
>  
> -	while ((uart->iu_lsr & 0x20) == 0);
> -	uart->iu_thr = c;
> +	while ((readb(&uart->iu_lsr) & 0x20) == 0)
> +		;
> +	writeb(c, &uart->iu_thr);
>  }
> diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c
> index 0cf6507de3c7..05f0d91366af 100644
> --- a/drivers/rtc/rtc-m48t35.c
> +++ b/drivers/rtc/rtc-m48t35.c
> @@ -24,6 +24,16 @@
>  
>  struct m48t35_rtc {
>  	u8	pad[0x7ff8];    /* starts at 0x7ff8 */
> +#ifdef CONFIG_SGI_IP27
> +	u8	hour;
> +	u8	min;
> +	u8	sec;
> +	u8	control;
> +	u8	year;
> +	u8	month;
> +	u8	date;
> +	u8	day;
> +#else
>  	u8	control;
>  	u8	sec;
>  	u8	min;
> @@ -32,6 +42,7 @@ struct m48t35_rtc {
>  	u8	date;
>  	u8	month;
>  	u8	year;
> +#endif
>  };
>  
>  #define M48T35_RTC_SET		0x80
> diff --git a/drivers/tty/serial/8250/8250_ioc3.c b/drivers/tty/serial/8250/8250_ioc3.c
> index 2be6ed2967e0..4c405f1b9c67 100644
> --- a/drivers/tty/serial/8250/8250_ioc3.c
> +++ b/drivers/tty/serial/8250/8250_ioc3.c
> @@ -23,12 +23,12 @@ struct ioc3_8250_data {
>  
>  static unsigned int ioc3_serial_in(struct uart_port *p, int offset)
>  {
> -	return readb(p->membase + offset);
> +	return readb(p->membase + (offset ^ 3));
>  }
>  
>  static void ioc3_serial_out(struct uart_port *p, int offset, int value)
>  {
> -	writeb(value, p->membase + offset);
> +	writeb(value, p->membase + (offset ^ 3));
>  }
>  
>  static int serial8250_ioc3_probe(struct platform_device *pdev)
> -- 
> 2.13.7
> 

-- 
Alexandre Belloni, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/4] mfd: ioc3: Add driver for SGI IOC3 chip
       [not found] ` <20190409154610.6735-3-tbogendoerfer@suse.de>
@ 2019-04-16 13:16   ` Greg Kroah-Hartman
  2019-05-08 10:23   ` Lee Jones
  1 sibling, 0 replies; 11+ messages in thread
From: Greg Kroah-Hartman @ 2019-04-16 13:16 UTC (permalink / raw)
  To: Thomas Bogendoerfer
  Cc: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
	Lee Jones, David S. Miller, Alessandro Zummo, Alexandre Belloni,
	Jiri Slaby, linux-mips, linux-kernel, linux-input, netdev,
	linux-rtc, linux-serial

On Tue, Apr 09, 2019 at 05:46:06PM +0200, Thomas Bogendoerfer wrote:
> SGI IOC3 chip has integrated ethernet, keyboard and mouse interface.
> It also supports connecting a SuperIO chip for serial and parallel
> interfaces. IOC3 is used inside various SGI systemboards and add-on
> cards with different equipped external interfaces.
> 
> Support for ethernet and serial interfaces were implemented inside
> the network driver. This patchset moves out the not network related
> parts to a new MFD driver, which takes care of card detection,
> setup of platform devices and interrupt distribution for the subdevices.
> 
> Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
> ---
>  arch/mips/include/asm/sn/ioc3.h       |  345 +++---
>  arch/mips/sgi-ip27/ip27-timer.c       |   20 -
>  drivers/mfd/Kconfig                   |   13 +
>  drivers/mfd/Makefile                  |    1 +
>  drivers/mfd/ioc3.c                    |  802 ++++++++++++++
>  drivers/net/ethernet/sgi/Kconfig      |    4 +-
>  drivers/net/ethernet/sgi/ioc3-eth.c   | 1867 ++++++++++++---------------------
>  drivers/tty/serial/8250/8250_ioc3.c   |   98 ++
>  drivers/tty/serial/8250/Kconfig       |   11 +
>  drivers/tty/serial/8250/Makefile      |    1 +
>  include/linux/platform_data/ioc3eth.h |   15 +
>  11 files changed, 1762 insertions(+), 1415 deletions(-)
>  create mode 100644 drivers/mfd/ioc3.c
>  create mode 100644 drivers/tty/serial/8250/8250_ioc3.c
>  create mode 100644 include/linux/platform_data/ioc3eth.h

Serial portion:

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/4] mfd: ioc3: Add driver for SGI IOC3 chip
       [not found] ` <20190409154610.6735-3-tbogendoerfer@suse.de>
  2019-04-16 13:16   ` [PATCH v2 2/4] mfd: ioc3: Add driver for SGI IOC3 chip Greg Kroah-Hartman
@ 2019-05-08 10:23   ` Lee Jones
  2019-05-09 14:02     ` Thomas Bogendoerfer
  2019-05-14 12:39     ` Esben Haabendal
  1 sibling, 2 replies; 11+ messages in thread
From: Lee Jones @ 2019-05-08 10:23 UTC (permalink / raw)
  To: Thomas Bogendoerfer
  Cc: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
	David S. Miller, Alessandro Zummo, Alexandre Belloni,
	Greg Kroah-Hartman, Jiri Slaby, linux-mips, linux-kernel,
	linux-input, netdev, linux-rtc, linux-serial

On Tue, 09 Apr 2019, Thomas Bogendoerfer wrote:

> SGI IOC3 chip has integrated ethernet, keyboard and mouse interface.
> It also supports connecting a SuperIO chip for serial and parallel
> interfaces. IOC3 is used inside various SGI systemboards and add-on
> cards with different equipped external interfaces.
> 
> Support for ethernet and serial interfaces were implemented inside
> the network driver. This patchset moves out the not network related
> parts to a new MFD driver, which takes care of card detection,
> setup of platform devices and interrupt distribution for the subdevices.
> 
> Signed-off-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
> ---
>  arch/mips/include/asm/sn/ioc3.h       |  345 +++---
>  arch/mips/sgi-ip27/ip27-timer.c       |   20 -
>  drivers/mfd/Kconfig                   |   13 +
>  drivers/mfd/Makefile                  |    1 +
>  drivers/mfd/ioc3.c                    |  802 ++++++++++++++
>  drivers/net/ethernet/sgi/Kconfig      |    4 +-
>  drivers/net/ethernet/sgi/ioc3-eth.c   | 1867 ++++++++++++---------------------
>  drivers/tty/serial/8250/8250_ioc3.c   |   98 ++
>  drivers/tty/serial/8250/Kconfig       |   11 +
>  drivers/tty/serial/8250/Makefile      |    1 +
>  include/linux/platform_data/ioc3eth.h |   15 +
>  11 files changed, 1762 insertions(+), 1415 deletions(-)
>  create mode 100644 drivers/mfd/ioc3.c
>  create mode 100644 drivers/tty/serial/8250/8250_ioc3.c
>  create mode 100644 include/linux/platform_data/ioc3eth.h

[...]

> +config SGI_MFD_IOC3
> +	tristate "SGI IOC3 core driver"
> +	depends on PCI && MIPS
> +	select MFD_CORE
> +	help
> +	  This option enables basic support for the SGI IOC3-based
> +	  controller cards.  This option does not enable any specific
> +	  functions on such a card, but provides necessary infrastructure
> +	  for other drivers to utilize.
> +
> +	  If you have an SGI Origin, Octane, or a PCI IOC3 card,
> +	  then say Y. Otherwise say N.
> +
>  endmenu
>  endif
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index b4569ed7f3f3..07255e499129 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -246,4 +246,5 @@ obj-$(CONFIG_MFD_MXS_LRADC)     += mxs-lradc.o
>  obj-$(CONFIG_MFD_SC27XX_PMIC)	+= sprd-sc27xx-spi.o
>  obj-$(CONFIG_RAVE_SP_CORE)	+= rave-sp.o
>  obj-$(CONFIG_MFD_ROHM_BD718XX)	+= rohm-bd718x7.o
> +obj-$(CONFIG_SGI_MFD_IOC3)	+= ioc3.o
>  
> diff --git a/drivers/mfd/ioc3.c b/drivers/mfd/ioc3.c
> new file mode 100644
> index 000000000000..ad715805b16e
> --- /dev/null
> +++ b/drivers/mfd/ioc3.c
> @@ -0,0 +1,802 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * SGI IOC3 multifunction device driver
> + *
> + * Copyright (C) 2018, 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de>
> + *
> + * Based on work by:
> + *   Stanislaw Skowronek <skylark@unaligned.org>
> + *   Joshua Kinard <kumba@gentoo.org>
> + *   Brent Casavant <bcasavan@sgi.com> - IOC4 master driver
> + *   Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer
> + */
> +
> +#include <linux/errno.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/interrupt.h>
> +#include <linux/delay.h>
> +#include <linux/mfd/core.h>
> +#include <linux/platform_device.h>
> +#include <linux/platform_data/ioc3eth.h>

These should be in alphabetical order.

> +#include <asm/sn/ioc3.h>
> +#include <asm/pci/bridge.h>
> +
> +#define IOC3_ETH	BIT(0)
> +#define IOC3_SER	BIT(1)
> +#define IOC3_PAR	BIT(2)
> +#define IOC3_KBD	BIT(3)
> +#define IOC3_M48T35	BIT(4)
> +
> +static int ioc3_serial_id = 1;
> +static int ioc3_eth_id = 1;
> +static int ioc3_kbd_id = 1;
> +static struct mfd_cell ioc3_mfd_cells[5];
> +
> +struct ioc3_board_info {
> +	const char *name;
> +	int irq_offset;
> +	int funcs;
> +};
> +
> +struct ioc3_priv_data {
> +	struct ioc3_board_info *info;
> +	struct irq_domain *domain;
> +	struct ioc3 __iomem *regs;
> +	struct pci_dev *pdev;
> +	char nic_part[32];
> +	char nic_mac[6];
> +	int irq_io;
> +};
> +
> +#define MCR_PACK(pulse, sample)	(((pulse) << 10) | ((sample) << 2))
> +
> +static int ioc3_nic_wait(u32 __iomem *mcr)
> +{
> +	u32 mcr_val;
> +
> +	do {
> +		mcr_val = readl(mcr);
> +	} while (!(mcr_val & 2));

Why 2?  Is bit 2 always set on a successful read?

Either way, you should provide a comment to improve readability.

> +	return (mcr_val & 1);

Reads just a bit at a time?  Again, a comment please.

> +}
> +
> +static int ioc3_nic_reset(u32 __iomem *mcr)
> +{
> +	int presence;
> +	unsigned long flags;
> +
> +	local_irq_save(flags);
> +	writel(MCR_PACK(520, 65), mcr);

What do these magic values mean?  Best to define them.

> +	presence = ioc3_nic_wait(mcr);
> +	local_irq_restore(flags);
> +
> +	udelay(500);

What are you waiting for?  Why 500us?

> +	return presence;
> +}
> +
> +static int ioc3_nic_read_bit(u32 __iomem *mcr)
> +{
> +	int result;
> +	unsigned long flags;
> +
> +	local_irq_save(flags);
> +	writel(MCR_PACK(6, 13), mcr);

Why 6 and 13?

Define all magic values please.

> +	result = ioc3_nic_wait(mcr);
> +	local_irq_restore(flags);
> +
> +	udelay(100);

Why 100?

> +	return result;
> +}
> +
> +static u32 ioc3_nic_read_byte(u32 __iomem *mcr)
> +{
> +	u32 result = 0;
> +	int i;
> +
> +	for (i = 0; i < 8; i++)
> +		result = ((result >> 1) | (ioc3_nic_read_bit(mcr) << 7));
> +
> +	return result;
> +}
> +
> +static void ioc3_nic_write_bit(u32 __iomem *mcr, int bit)
> +{
> +	if (bit)
> +		writel(MCR_PACK(6, 110), mcr);
> +	else
> +		writel(MCR_PACK(80, 30), mcr);
> +
> +	ioc3_nic_wait(mcr);
> +}
> +
> +static void ioc3_nic_write_byte(u32 __iomem *mcr, int byte)
> +{
> +	int i;
> +
> +	for (i = 0; i < 8; i++) {
> +		ioc3_nic_write_bit(mcr, byte & 1);
> +		byte >>= 1;
> +	}
> +}
> +
> +static u64 ioc3_nic_find(u32 __iomem *mcr, int *last, u64 addr)
> +{
> +	int a, b, index, disc;
> +
> +	ioc3_nic_reset(mcr);
> +
> +	/* Search ROM.  */
> +	ioc3_nic_write_byte(mcr, 0xf0);

What does 0xf0 mean?

Please define it and all magic numbers that follow.

> +	/* Algorithm from ``Book of iButton Standards''.  */

That's great, but what is it actually doing.  Please provide suitable
comments such that the reader doesn't have to painstakingly work it
all out.

> +	for (index = 0, disc = 0; index < 64; index++) {
> +		a = ioc3_nic_read_bit(mcr);
> +		b = ioc3_nic_read_bit(mcr);
> +
> +		if (unlikely(a && b)) {
> +			pr_warn("ioc3: NIC search failed.\n");
> +			*last = 0;
> +			return 0;
> +		}
> +
> +		if (!a && !b) {
> +			if (index == *last)
> +				addr |= 1UL << index;
> +			else if (index > *last) {
> +				addr &= ~(1UL << index);
> +				disc = index;
> +			} else if ((addr & (1UL << index)) == 0)
> +				disc = index;
> +			ioc3_nic_write_bit(mcr, (addr >> index) & 1);
> +			continue;
> +		} else {
> +			if (a)
> +				addr |= (1UL << index);
> +			else
> +				addr &= ~(1UL << index);
> +			ioc3_nic_write_bit(mcr, a);
> +			continue;
> +		}
> +	}
> +	*last = disc;
> +	return addr;
> +}
> +
> +static void ioc3_nic_addr(u32 __iomem *mcr, u64 addr)
> +{
> +	int index;
> +
> +	ioc3_nic_reset(mcr);
> +	ioc3_nic_write_byte(mcr, 0xf0);
> +
> +	for (index = 0; index < 64; index++) {
> +		ioc3_nic_read_bit(mcr);
> +		ioc3_nic_read_bit(mcr);
> +		ioc3_nic_write_bit(mcr, ((addr >> index) & 1));
> +	}

What is this function doing?  Setting the NIC address?

Why are the 2 sequential reads required before each bit write?

> +}
> +
> +static void crc16_byte(u32 *crc, u8 db)
> +{
> +	int i;
> +
> +	for (i = 0; i < 8; i++) {
> +		*crc <<= 1;
> +		if ((db ^ (*crc >> 16)) & 1)
> +			*crc ^= 0x8005;
> +		db >>= 1;
> +	}
> +	*crc &= 0xffff;
> +}
> +
> +static u32 crc16_area(u8 *dbs, int size, u32 crc)
> +{
> +	while (size--)
> +		crc16_byte(&crc, *(dbs++));
> +
> +	return crc;
> +}
> +
> +static void crc8_byte(u32 *crc, u8 db)
> +{
> +	int i, f;
> +
> +	for (i = 0; i < 8; i++) {
> +		f = ((*crc ^ db) & 1);
> +		*crc >>= 1;
> +		db >>= 1;
> +		if (f)
> +			*crc ^= 0x8c;
> +	}
> +	*crc &= 0xff;
> +}
> +
> +static u32 crc8_addr(u64 addr)
> +{
> +	u32 crc = 0;
> +	int i;
> +
> +	for (i = 0; i < 64; i += 8)
> +		crc8_byte(&crc, addr >> i);
> +	return crc;
> +}

Not looked into these in any detail, but are you not able to use the
CRC functions already provided by the kernel?

> +static void ioc3_read_redir_page(u32 __iomem *mcr, u64 addr, int page,

What is a redir page?

> +				 u8 *redir, u8 *data)
> +{
> +	int loops = 16, i;
> +
> +	while (redir[page] != 0xff) {
> +		page = (redir[page] ^ 0xff);
> +		loops--;
> +		if (unlikely(loops < 0)) {
> +			pr_err("ioc3: NIC circular redirection\n");
> +			return;
> +		}
> +	}
> +
> +	loops = 3;
> +	while (loops > 0) {
> +		ioc3_nic_addr(mcr, addr);
> +		ioc3_nic_write_byte(mcr, 0xf0);
> +		ioc3_nic_write_byte(mcr, (page << 5) & 0xe0);
> +		ioc3_nic_write_byte(mcr, (page >> 3) & 0x1f);
> +
> +		for (i = 0; i < 0x20; i++)
> +			data[i] = ioc3_nic_read_byte(mcr);
> +
> +		if (crc16_area(data, 0x20, 0) == 0x800d)
> +			return;
> +
> +		loops--;
> +	}
> +
> +	pr_err("ioc3: CRC error in data page\n");
> +	for (i = 0; i < 0x20; i++)
> +		data[i] = 0x00;

Comments required throughout.

> +}
> +
> +static void ioc3_read_redir_map(u32 __iomem *mcr, u64 addr, u8 *redir)
> +{
> +	int i, j, crc_ok, loops = 3;
> +	u32 crc;
> +
> +	while (loops > 0) {
> +		crc_ok = 1;
> +		ioc3_nic_addr(mcr, addr);
> +		ioc3_nic_write_byte(mcr, 0xaa);
> +		ioc3_nic_write_byte(mcr, 0x00);
> +		ioc3_nic_write_byte(mcr, 0x01);
> +
> +		for (i = 0; i < 64; i += 8) {
> +			for (j = 0; j < 8; j++)
> +				redir[i + j] = ioc3_nic_read_byte(mcr);
> +
> +			crc = crc16_area(redir + i, 8, i == 0 ? 0x8707 : 0);
> +
> +			crc16_byte(&crc, ioc3_nic_read_byte(mcr));
> +			crc16_byte(&crc, ioc3_nic_read_byte(mcr));
> +
> +			if (crc != 0x800d)
> +				crc_ok = 0;
> +		}
> +		if (crc_ok)
> +			return;
> +		loops--;
> +	}
> +	pr_err("ioc3: CRC error in redirection page\n");
> +	for (i = 0; i < 64; i++)
> +		redir[i] = 0xff;

As above.

> +}
> +
> +static void ioc3_read_nic(struct ioc3_priv_data *ipd, u32 __iomem *mcr,
> +			  u64 addr)
> +{
> +	u8 redir[64];
> +	u8 data[64], part[32];
> +	int i, j;
> +
> +	/* Read redirections */
> +	ioc3_read_redir_map(mcr, addr, redir);
> +
> +	/* Read data pages */
> +	ioc3_read_redir_page(mcr, addr, 0, redir, data);
> +	ioc3_read_redir_page(mcr, addr, 1, redir, (data + 32));
> +
> +	/* Assemble the part # */
> +	j = 0;
> +	for (i = 0; i < 19; i++)
> +		if (data[i + 11] != ' ')
> +			part[j++] = data[i + 11];
> +
> +	for (i = 0; i < 6; i++)
> +		if (data[i + 32] != ' ')
> +			part[j++] = data[i + 32];
> +
> +	part[j] = 0;
> +
> +	/* Skip Octane (IP30) power supplies */
> +	if (!(strncmp(part, "060-0035-", 9)) ||
> +	    !(strncmp(part, "060-0038-", 9)) ||
> +	    !(strncmp(part, "060-0028-", 9)))
> +		return;
> +
> +	strlcpy(ipd->nic_part, part, sizeof(ipd->nic_part));
> +}
> +
> +static void ioc3_read_mac(struct ioc3_priv_data *ipd, u64 addr)
> +{
> +	int i, loops = 3;
> +	u8 data[13];
> +	u32 __iomem *mcr = &ipd->regs->mcr;
> +
> +	while (loops > 0) {
> +		ioc3_nic_addr(mcr, addr);
> +		ioc3_nic_write_byte(mcr, 0xf0);
> +		ioc3_nic_write_byte(mcr, 0x00);
> +		ioc3_nic_write_byte(mcr, 0x00);
> +		ioc3_nic_read_byte(mcr);
> +
> +		for (i = 0; i < 13; i++)
> +			data[i] = ioc3_nic_read_byte(mcr);
> +
> +		if (crc16_area(data, 13, 0) == 0x800d) {
> +			for (i = 10; i > 4; i--)
> +				ipd->nic_mac[10 - i] = data[i];
> +			return;
> +		}
> +		loops--;
> +	}
> +
> +	pr_err("ioc3: CRC error in MAC address\n");
> +	for (i = 0; i < 6; i++)
> +		ipd->nic_mac[i] = 0x00;
> +}
> +
> +static void ioc3_probe_nic(struct ioc3_priv_data *ipd, u32 __iomem *mcr)
> +{
> +	int save = 0, loops = 3;
> +	u64 first, addr;
> +
> +	while (loops > 0) {
> +		ipd->nic_part[0] = 0;
> +		first = ioc3_nic_find(mcr, &save, 0);
> +		addr = first;
> +
> +		if (unlikely(!first))
> +			return;
> +
> +		while (1) {
> +			if (crc8_addr(addr))
> +				break;
> +
> +			switch (addr & 0xff) {
> +			case 0x0b:
> +				ioc3_read_nic(ipd, mcr, addr);
> +				break;
> +			case 0x09:
> +			case 0x89:
> +			case 0x91:
> +				ioc3_read_mac(ipd, addr);
> +				break;
> +			}
> +
> +			addr = ioc3_nic_find(mcr, &save, addr);
> +			if (addr == first)
> +				return;
> +		}
> +		loops--;
> +	}
> +	pr_err("ioc3: CRC error in NIC address\n");
> +}

This all looks like networking code.  If this is the case, it should
be moved to drivers/networking or similar.

> +static void ioc3_irq_ack(struct irq_data *d)
> +{
> +	struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d);
> +	unsigned int hwirq = irqd_to_hwirq(d);
> +
> +	writel(BIT(hwirq), &ipd->regs->sio_ir);
> +}
> +
> +static void ioc3_irq_mask(struct irq_data *d)
> +{
> +	struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d);
> +	unsigned int hwirq = irqd_to_hwirq(d);
> +
> +	writel(BIT(hwirq), &ipd->regs->sio_iec);
> +}
> +
> +static void ioc3_irq_unmask(struct irq_data *d)
> +{
> +	struct ioc3_priv_data *ipd = irq_data_get_irq_chip_data(d);
> +	unsigned int hwirq = irqd_to_hwirq(d);
> +
> +	writel(BIT(hwirq), &ipd->regs->sio_ies);
> +}
> +
> +static struct irq_chip ioc3_irq_chip = {
> +	.name		= "IOC3",
> +	.irq_ack	= ioc3_irq_ack,
> +	.irq_mask	= ioc3_irq_mask,
> +	.irq_unmask	= ioc3_irq_unmask,
> +};
> +
> +#define IOC3_LVL_MASK	(BIT(0) | BIT(2) | BIT(6) | BIT(9) | BIT(11) | BIT(15))

You need to define what each of these bits are.  BIT(2) doesn't tell
the reader anything, meaning the code is unreadable.

> +static int ioc3_irq_domain_map(struct irq_domain *d, unsigned int irq,
> +			      irq_hw_number_t hwirq)
> +{
> +	if (BIT(hwirq) & IOC3_LVL_MASK)

Comment needed.

> +		irq_set_chip_and_handler(irq, &ioc3_irq_chip, handle_level_irq);
> +	else
> +		irq_set_chip_and_handler(irq, &ioc3_irq_chip, handle_edge_irq);
> +
> +	irq_set_chip_data(irq, d->host_data);
> +	return 0;
> +}
> +
> +

Drop the superfluous '\n'.

> +static const struct irq_domain_ops ioc3_irq_domain_ops = {
> +	.map = ioc3_irq_domain_map,
> +};
> +
> +static void ioc3_irq_handler(struct irq_desc *desc)
> +{
> +	struct irq_domain *domain = irq_desc_get_handler_data(desc);
> +	struct ioc3_priv_data *ipd = domain->host_data;
> +	struct ioc3 __iomem *regs = ipd->regs;
> +	unsigned int irq = 0;

Why does these need to be pre-assigned?

> +	u32 pending;
> +
> +	pending = readl(&regs->sio_ir);
> +	pending &= readl(&regs->sio_ies);

Comment required.

> +	if (pending)
> +		irq = irq_find_mapping(domain, __ffs(pending));
> +	else if (!ipd->info->irq_offset &&
> +		 (readl(&regs->eth.eisr) & readl(&regs->eth.eier)))

Comment required.

> +		irq = irq_find_mapping(domain, 23);
> +
> +	if (irq)
> +		generic_handle_irq(irq);
> +	else
> +		spurious_interrupt();
> +}
> +
> +static struct resource ioc3_uarta_resources[] = {
> +	DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uarta),

You are the first user of offsetof() in MFD.  Could you tell me why
it's required please?

> +		       sizeof_field(struct ioc3, sregs.uarta)),
> +	DEFINE_RES_IRQ(6)

Please define all magic numbers.

> +};
> +
> +static struct resource ioc3_uartb_resources[] = {
> +	DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uartb),
> +		       sizeof_field(struct ioc3, sregs.uartb)),
> +	DEFINE_RES_IRQ(15)
> +};
> +
> +static struct resource ioc3_kbd_resources[] = {
> +	DEFINE_RES_MEM(offsetof(struct ioc3, serio),
> +		       sizeof_field(struct ioc3, serio)),
> +	DEFINE_RES_IRQ(22)
> +};
> +
> +static struct resource ioc3_eth_resources[] = {
> +	DEFINE_RES_MEM(offsetof(struct ioc3, eth),
> +		       sizeof_field(struct ioc3, eth)),
> +	DEFINE_RES_MEM(offsetof(struct ioc3, ssram),
> +		       sizeof_field(struct ioc3, ssram)),
> +	DEFINE_RES_IRQ(0)
> +};
> +
> +static struct ioc3eth_platform_data ioc3_eth_platform_data;

I doubt you'll need this in here.  The MAC address info will need to
be moved out to a networking driver of some sort.

> +#ifdef CONFIG_SGI_IP27

#ifery in C files is highly discouraged.  Please remove them.

> +static struct resource ioc3_rtc_resources[] = {
> +	DEFINE_RES_MEM(IOC3_BYTEBUS_DEV0, 32768)

Define all magic numbers please.

> +};
> +
> +static struct ioc3_board_info ip27_baseio_info = {
> +	.name = "IP27 BaseIO",
> +	.funcs = IOC3_ETH | IOC3_SER | IOC3_M48T35,
> +	.irq_offset = 2
> +};
> +
> +static struct ioc3_board_info ip27_baseio6g_info = {
> +	.name = "IP27 BaseIO6G",
> +	.funcs = IOC3_ETH | IOC3_SER | IOC3_KBD | IOC3_M48T35,
> +	.irq_offset = 2
> +};
> +
> +static struct ioc3_board_info ip27_mio_info = {
> +	.name = "MIO",
> +	.funcs = IOC3_SER | IOC3_PAR | IOC3_KBD,
> +	.irq_offset = 0
> +};
> +
> +static struct ioc3_board_info ip29_baseio_info = {
> +	.name = "IP29 System Board",
> +	.funcs = IOC3_ETH | IOC3_SER | IOC3_PAR | IOC3_KBD | IOC3_M48T35,
> +	.irq_offset = 1
> +};
> +
> +#endif /* CONFIG_SGI_IP27 */
> +
> +static struct ioc3_board_info ioc3_menet_info = {
> +	.name = "MENET",
> +	.funcs = IOC3_ETH | IOC3_SER,
> +	.irq_offset = 4
> +};
> +
> +static struct ioc3_board_info ioc3_cad_duo_info = {
> +	.name = "CAD DUO",
> +	.funcs = IOC3_ETH | IOC3_KBD,
> +	.irq_offset = 0
> +};

Please drop all of these and statically create the MFD cells like
almost all other MFD drivers do.

> +#define IOC3_BOARD(_partno, _info) {   .info = _info, .match = _partno }
> +
> +static struct {
> +	struct ioc3_board_info *info;
> +	const char *match;
> +} ioc3_boards[] = {
> +#ifdef CONFIG_SGI_IP27
> +	IOC3_BOARD("030-0734-", &ip27_baseio6g_info),
> +	IOC3_BOARD("030-1023-", &ip27_baseio_info),
> +	IOC3_BOARD("030-1124-", &ip27_baseio_info),
> +	IOC3_BOARD("030-1025-", &ip29_baseio_info),
> +	IOC3_BOARD("030-1244-", &ip29_baseio_info),
> +	IOC3_BOARD("030-1389-", &ip29_baseio_info),
> +	IOC3_BOARD("030-0880-", &ip27_mio_info),
> +#endif
> +	IOC3_BOARD("030-0873-", &ioc3_menet_info),
> +	IOC3_BOARD("030-1155-", &ioc3_cad_duo_info),
> +};
> +
> +static int ioc3_identify(struct ioc3_priv_data *idp)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(ioc3_boards); i++)
> +		if (!strncmp(idp->nic_part, ioc3_boards[i].match,
> +			     strlen(ioc3_boards[i].match))) {
> +			idp->info = ioc3_boards[i].info;
> +			return 0;
> +		}
> +
> +	return -1;

Please return a proper Linux error code.

> +}
> +
> +static void ioc3_create_devices(struct ioc3_priv_data *ipd)
> +{
> +	struct mfd_cell *cell;
> +
> +	memset(ioc3_mfd_cells, 0, sizeof(ioc3_mfd_cells));
> +	cell = ioc3_mfd_cells;
> +
> +	if (ipd->info->funcs & IOC3_ETH) {
> +		memcpy(ioc3_eth_platform_data.mac_addr, ipd->nic_mac,
> +		       sizeof(ioc3_eth_platform_data.mac_addr));

Better to pull the MAC address from within the Ethernet driver.

> +		cell->name = "ioc3-eth";
> +		cell->id = ioc3_eth_id++;
> +		cell->resources = ioc3_eth_resources;
> +		cell->num_resources = ARRAY_SIZE(ioc3_eth_resources);
> +		cell->platform_data = &ioc3_eth_platform_data;
> +		cell->pdata_size = sizeof(ioc3_eth_platform_data);

Please define all of this in a static struct, external to this
function.

> +		if (ipd->info->irq_offset) {
> +			/*
> +			 * Ethernet interrupt is on an extra interrupt
> +			 * not inside the irq domain, so we need an
> +			 * extra mfd_add_devices without the domain
> +			 * argument
> +			 */
> +			ioc3_eth_resources[2].start = ipd->pdev->irq;
> +			ioc3_eth_resources[2].end = ipd->pdev->irq;

Using '2' is fragile.

In this case, seeing as you're using the parent's IRQ, you can obtain
the IRQ using the usual platform_*() handlers, using pdev->parent.

> +			mfd_add_devices(&ipd->pdev->dev, -1, cell, 1,

Don't use -1, use the defines instead.

Instead of 1, use ARRAY_SIZE() once the cells are defined statically.

> +					&ipd->pdev->resource[0], 0, NULL);
> +			memset(cell, 0, sizeof(*cell));
> +		} else {
> +			/* fake hwirq in domain */

What does this mean?

> +			ioc3_eth_resources[2].start = 23;
> +			ioc3_eth_resources[2].end = 23;
> +			cell++;
> +		}
> +	}
> +	if (ipd->info->funcs & IOC3_SER) {
> +		writel(GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL,
> +			&ipd->regs->gpcr_s);
> +		writel(0, &ipd->regs->gppr[6]);
> +		writel(0, &ipd->regs->gppr[7]);
> +		udelay(100);
> +		writel(readl(&ipd->regs->port_a.sscr) & ~SSCR_DMA_EN,
> +		       &ipd->regs->port_a.sscr);
> +		writel(readl(&ipd->regs->port_b.sscr) & ~SSCR_DMA_EN,
> +		       &ipd->regs->port_b.sscr);
> +		udelay(1000);

No idea what any of this does.

It looks like it belongs in the serial driver (and needs comments).

> +		cell->name = "ioc3-serial8250";
> +		cell->id = ioc3_serial_id++;
> +		cell->resources = ioc3_uarta_resources;
> +		cell->num_resources = ARRAY_SIZE(ioc3_uarta_resources);
> +		cell++;
> +		cell->name = "ioc3-serial8250";
> +		cell->id = ioc3_serial_id++;
> +		cell->resources = ioc3_uartb_resources;
> +		cell->num_resources = ARRAY_SIZE(ioc3_uartb_resources);
> +		cell++;

Please define this statically.

> +	}
> +	if (ipd->info->funcs & IOC3_KBD) {
> +		cell->name = "ioc3-kbd",
> +		cell->id = ioc3_kbd_id++;
> +		cell->resources = ioc3_kbd_resources,
> +		cell->num_resources = ARRAY_SIZE(ioc3_kbd_resources),
> +		cell++;

As above.

> +	}
> +#if defined(CONFIG_SGI_IP27)

What is this?  Can't you obtain this dynamically by probing the H/W?

> +	if (ipd->info->funcs & IOC3_M48T35) {
> +		cell->name = "rtc-m48t35";
> +		cell->id = -1;
> +		cell->resources = ioc3_rtc_resources;
> +		cell->num_resources = ARRAY_SIZE(ioc3_rtc_resources);
> +		cell++;

Static please.

> +	}
> +#endif
> +	mfd_add_devices(&ipd->pdev->dev, -1, ioc3_mfd_cells,

Use the defines.

> +			cell - ioc3_mfd_cells, &ipd->pdev->resource[0],

?

> +			0, ipd->domain);
> +}
> +
> +static int ioc3_mfd_probe(struct pci_dev *pdev,
> +			  const struct pci_device_id *pci_id)
> +{
> +	struct ioc3_priv_data *ipd;
> +	int err, ret = -ENODEV, io_irqno;
> +	struct ioc3 __iomem *regs;
> +	struct irq_domain *domain;
> +	struct fwnode_handle *fn;
> +
> +	err = pci_enable_device(pdev);
> +	if (err)
> +		return err;
> +
> +	pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64);
> +	pci_set_master(pdev);
> +
> +	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
> +	if (ret) {
> +		dev_warn(&pdev->dev, "Warning: couldn_t set 64-bit DMA mask\n");
> +		ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
> +		if (ret) {
> +			dev_err(&pdev->dev, "Can't set DMA mask, aborting\n");
> +			return ret;
> +		}
> +	}
> +
> +	/* Set up per-IOC3 data */
> +	ipd = kzalloc(sizeof(struct ioc3_priv_data), GFP_KERNEL);

Does PCI not provide managed (devm_*() like) helpers?

> +	if (!ipd) {
> +		ret = -ENOMEM;
> +		goto out_disable_device;
> +	}
> +	ipd->pdev = pdev;

'\n'

> +	/*
> +	 * Map all IOC3 registers.  These are shared between subdevices
> +	 * so the main IOC3 module manages them.
> +	 */
> +	regs = pci_ioremap_bar(pdev, 0);
> +	if (!regs) {
> +		pr_warn("ioc3: Unable to remap PCI BAR for %s.\n",
> +			pci_name(pdev));
> +		goto out_free_ipd;
> +	}
> +	ipd->regs = regs;
> +
> +	/* Track PCI-device specific data */
> +	pci_set_drvdata(pdev, ipd);

Do you don't need 'ipd->pdev = pdev' then.

> +	writel(GPCR_MLAN_EN, &ipd->regs->gpcr_s);
> +	ioc3_probe_nic(ipd, &regs->mcr);

This should probably be moved to the networking driver.

> +#ifdef CONFIG_SGI_IP27

No #ifery in MFD c-files please.

> +	/* BaseIO NIC is attached to bridge */
> +	if (!ipd->nic_part[0]) {
> +		struct bridge_controller *bc = BRIDGE_CONTROLLER(pdev->bus);
> +
> +		ioc3_probe_nic(ipd, &bc->base->b_nic);
> +	}
> +#endif
> +
> +	if (ioc3_identify(ipd)) {
> +		pr_err("ioc3: part: [%s] unknown card\n", ipd->nic_part);
> +		goto out_iounmap;
> +	}
> +
> +	pr_info("ioc3: part: [%s] %s\n", ipd->nic_part, ipd->info->name);
> +
> +	/* Clear IRQs */

A comment!  I just fell off my chair! =;-)

> +	writel(~0, &regs->sio_iec);
> +	writel(~0, &regs->sio_ir);
> +	writel(0, &regs->eth.eier);
> +	writel(~0, &regs->eth.eisr);
> +
> +	if (ipd->info->irq_offset) {

What does this really signify?

> +		struct pci_host_bridge *hbrg = pci_find_host_bridge(pdev->bus);
> +
> +		io_irqno = hbrg->map_irq(pdev,
> +			PCI_SLOT(pdev->devfn) + ipd->info->irq_offset, 0);
> +	} else {
> +		io_irqno = pdev->irq;
> +	}
> +	ipd->irq_io = io_irqno;
> +
> +	fn = irq_domain_alloc_named_fwnode("IOC3");
> +	if (!fn)
> +		goto out_iounmap;
> +
> +	domain = irq_domain_create_linear(fn, 24, &ioc3_irq_domain_ops, ipd);
> +	irq_domain_free_fwnode(fn);
> +	if (!domain)
> +		goto out_iounmap;
> +	ipd->domain = domain;
> +
> +	irq_set_chained_handler_and_data(io_irqno, ioc3_irq_handler, domain);
> +
> +	ioc3_create_devices(ipd);
> +
> +	return 0;
> +
> +out_iounmap:
> +	iounmap(ipd->regs);
> +
> +out_free_ipd:
> +	kfree(ipd);
> +
> +out_disable_device:
> +	pci_disable_device(pdev);
> +	return ret;
> +}
> +
> +static void ioc3_mfd_remove(struct pci_dev *pdev)
> +{
> +	struct ioc3_priv_data *ipd;
> +
> +	ipd = pci_get_drvdata(pdev);
> +
> +	/* Clear and disable all IRQs */
> +	writel(~0, &ipd->regs->sio_iec);
> +	writel(~0, &ipd->regs->sio_ir);
> +
> +	/* Release resources */
> +	irq_domain_remove(ipd->domain);
> +	free_irq(ipd->irq_io, (void *)ipd);
> +	iounmap(ipd->regs);
> +
> +	pci_disable_device(pdev);
> +
> +	kfree(ipd);
> +}
> +
> +static struct pci_device_id ioc3_mfd_id_table[] = {
> +	{ PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, PCI_ANY_ID, PCI_ANY_ID },
> +	{ 0, },
> +};
> +MODULE_DEVICE_TABLE(pci, ioc3_mfd_id_table);
> +
> +static struct pci_driver ioc3_mfd_driver = {
> +	.name = "IOC3",
> +	.id_table = ioc3_mfd_id_table,
> +	.probe = ioc3_mfd_probe,
> +	.remove = ioc3_mfd_remove,
> +};
> +
> +module_pci_driver(ioc3_mfd_driver);
> +
> +MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>");
> +MODULE_DESCRIPTION("SGI IOC3 MFD driver");
> +MODULE_LICENSE("GPL");

-- 
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/4] mfd: ioc3: Add driver for SGI IOC3 chip
  2019-05-08 10:23   ` Lee Jones
@ 2019-05-09 14:02     ` Thomas Bogendoerfer
  2019-05-10  7:14       ` Lee Jones
  2019-05-14 12:39     ` Esben Haabendal
  1 sibling, 1 reply; 11+ messages in thread
From: Thomas Bogendoerfer @ 2019-05-09 14:02 UTC (permalink / raw)
  To: Lee Jones
  Cc: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
	David S. Miller, Alessandro Zummo, Alexandre Belloni,
	Greg Kroah-Hartman, Jiri Slaby, linux-mips, linux-kernel,
	linux-input, netdev, linux-rtc, linux-serial

On Wed, 8 May 2019 11:23:13 +0100
Lee Jones <lee.jones@linaro.org> wrote:

> On Tue, 09 Apr 2019, Thomas Bogendoerfer wrote:
> 
> > +static u32 crc8_addr(u64 addr)
> > +{
> > +	u32 crc = 0;
> > +	int i;
> > +
> > +	for (i = 0; i < 64; i += 8)
> > +		crc8_byte(&crc, addr >> i);
> > +	return crc;
> > +}
> 
> Not looked into these in any detail, but are you not able to use the
> CRC functions already provided by the kernel?

they are using a different polynomial, so I can't use it.

> > +	}
> > +	pr_err("ioc3: CRC error in NIC address\n");
> > +}
> 
> This all looks like networking code.  If this is the case, it should
> be moved to drivers/networking or similar.

no it's not. nic stands for number in a can produced by Dallas Semi also
known under the name 1-Wire (https://en.wikipedia.org/wiki/1-Wire).
SGI used them to provide partnumber, serialnumber and mac addresses.
By placing the code to read the NiCs inside ioc3 driver there is no need
for locking and adding library code for accessing these informations.

> > +static struct resource ioc3_uarta_resources[] = {
> > +	DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uarta),
> 
> You are the first user of offsetof() in MFD.  Could you tell me why
> it's required please?

to get the offsets of different chip functions out of a struct.

> Please drop all of these and statically create the MFD cells like
> almost all other MFD drivers do.

I started that way and it blew up the driver and create a bigger mess
than I wanted to have. What's your concern with my approach ?

I could use static mfd_cell arrays, if there would be a init/startup
method per cell, which is called before setting up the platform device.
That way I could do the dynamic setup for ethernet and serial devices.

> > +static void ioc3_create_devices(struct ioc3_priv_data *ipd)
> > +{
> > +	struct mfd_cell *cell;
> > +
> > +	memset(ioc3_mfd_cells, 0, sizeof(ioc3_mfd_cells));
> > +	cell = ioc3_mfd_cells;
> > +
> > +	if (ipd->info->funcs & IOC3_ETH) {
> > +		memcpy(ioc3_eth_platform_data.mac_addr, ipd->nic_mac,
> > +		       sizeof(ioc3_eth_platform_data.mac_addr));
> 
> Better to pull the MAC address from within the Ethernet driver.

the NiC where the MAC address is provided is connected to the ioc3
chip outside of the ethernet register set. And there is another
NiC connected to the same 1-W bus. So moving reading of the MAC
address to the ethernet driver duplicates code and adds complexity
(locking). Again what's your concern here ?

> > +	if (ipd->info->funcs & IOC3_SER) {
> > +		writel(GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL,
> > +			&ipd->regs->gpcr_s);
> > +		writel(0, &ipd->regs->gppr[6]);
> > +		writel(0, &ipd->regs->gppr[7]);
> > +		udelay(100);
> > +		writel(readl(&ipd->regs->port_a.sscr) & ~SSCR_DMA_EN,
> > +		       &ipd->regs->port_a.sscr);
> > +		writel(readl(&ipd->regs->port_b.sscr) & ~SSCR_DMA_EN,
> > +		       &ipd->regs->port_b.sscr);
> > +		udelay(1000);
> 
> No idea what any of this does.
> 
> It looks like it belongs in the serial driver (and needs comments).

it configures the IOC3 chip for serial usage. This is not part of
the serial register set, so it IMHO belongs in the MFD driver.

> > +	}
> > +#if defined(CONFIG_SGI_IP27)
> 
> What is this?  Can't you obtain this dynamically by probing the H/W?

that's the machine type and the #ifdef CONFIG_xxx are just for saving space,
when compiled for other machines and it's easy to remove.

> > +	if (ipd->info->irq_offset) {
> 
> What does this really signify?

IOC3 ASICs are most of the time connected to a SGI bridge chip. IOC3 can
provide two interrupt lines, which are wired to the bridge chip. The first
interrupt is assigned via the PCI core, but since IOC3 is not a PCI multi
function device the second interrupt must be treated here. And the used
interrupt line on the bridge chip differs between boards.

Thank you for your review. I'll address all other comments not cited in
my mail.

Thomas.

-- 
SUSE Linux GmbH
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah
HRB 21284 (AG Nürnberg)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/4] mfd: ioc3: Add driver for SGI IOC3 chip
  2019-05-09 14:02     ` Thomas Bogendoerfer
@ 2019-05-10  7:14       ` Lee Jones
  2019-05-14 14:29         ` Thomas Bogendoerfer
  0 siblings, 1 reply; 11+ messages in thread
From: Lee Jones @ 2019-05-10  7:14 UTC (permalink / raw)
  To: Thomas Bogendoerfer
  Cc: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
	David S. Miller, Alessandro Zummo, Alexandre Belloni,
	Greg Kroah-Hartman, Jiri Slaby, linux-mips, linux-kernel,
	linux-input, netdev, linux-rtc, linux-serial

On Thu, 09 May 2019, Thomas Bogendoerfer wrote:

> On Wed, 8 May 2019 11:23:13 +0100
> Lee Jones <lee.jones@linaro.org> wrote:
> 
> > On Tue, 09 Apr 2019, Thomas Bogendoerfer wrote:
> > 
> > > +static u32 crc8_addr(u64 addr)
> > > +{
> > > +	u32 crc = 0;
> > > +	int i;
> > > +
> > > +	for (i = 0; i < 64; i += 8)
> > > +		crc8_byte(&crc, addr >> i);
> > > +	return crc;
> > > +}
> > 
> > Not looked into these in any detail, but are you not able to use the
> > CRC functions already provided by the kernel?
> 
> they are using a different polynomial, so I can't use it.

Would it be worth moving support out to somewhere more central so
others can use this "polynomial"?

> > > +	}
> > > +	pr_err("ioc3: CRC error in NIC address\n");
> > > +}
> > 
> > This all looks like networking code.  If this is the case, it should
> > be moved to drivers/networking or similar.
> 
> no it's not. nic stands for number in a can produced by Dallas Semi also
> known under the name 1-Wire (https://en.wikipedia.org/wiki/1-Wire).
> SGI used them to provide partnumber, serialnumber and mac addresses.
> By placing the code to read the NiCs inside ioc3 driver there is no need
> for locking and adding library code for accessing these informations.

Great.  So it looks like you should be using this, no?

  drivers/base/regmap/regmap-w1.c

> > > +static struct resource ioc3_uarta_resources[] = {
> > > +	DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uarta),
> > 
> > You are the first user of offsetof() in MFD.  Could you tell me why
> > it's required please?
> 
> to get the offsets of different chip functions out of a struct.

I can see what it does on a coding level.

What are you using it for in practical/real terms?

Why wouldn't any other MFD driver require this, but you do?

> > Please drop all of these and statically create the MFD cells like
> > almost all other MFD drivers do.
> 
> I started that way and it blew up the driver and create a bigger mess
> than I wanted to have. What's your concern with my approach ?
> 
> I could use static mfd_cell arrays, if there would be a init/startup
> method per cell, which is called before setting up the platform device.
> That way I could do the dynamic setup for ethernet and serial devices.

You can set platform data later.  There are plenty of examples of
this in the MFD subsystem.  Statically define what you can, and add
the dynamic stuff later.

> > > +static void ioc3_create_devices(struct ioc3_priv_data *ipd)
> > > +{
> > > +	struct mfd_cell *cell;
> > > +
> > > +	memset(ioc3_mfd_cells, 0, sizeof(ioc3_mfd_cells));
> > > +	cell = ioc3_mfd_cells;
> > > +
> > > +	if (ipd->info->funcs & IOC3_ETH) {
> > > +		memcpy(ioc3_eth_platform_data.mac_addr, ipd->nic_mac,
> > > +		       sizeof(ioc3_eth_platform_data.mac_addr));
> > 
> > Better to pull the MAC address from within the Ethernet driver.
> 
> the NiC where the MAC address is provided is connected to the ioc3
> chip outside of the ethernet register set. And there is another
> NiC connected to the same 1-W bus. So moving reading of the MAC
> address to the ethernet driver duplicates code and adds complexity
> (locking). Again what's your concern here ?

Does this go away if you use the already provided 1-wire API?

> > > +	if (ipd->info->funcs & IOC3_SER) {
> > > +		writel(GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL,
> > > +			&ipd->regs->gpcr_s);
> > > +		writel(0, &ipd->regs->gppr[6]);
> > > +		writel(0, &ipd->regs->gppr[7]);
> > > +		udelay(100);
> > > +		writel(readl(&ipd->regs->port_a.sscr) & ~SSCR_DMA_EN,
> > > +		       &ipd->regs->port_a.sscr);
> > > +		writel(readl(&ipd->regs->port_b.sscr) & ~SSCR_DMA_EN,
> > > +		       &ipd->regs->port_b.sscr);
> > > +		udelay(1000);
> > 
> > No idea what any of this does.
> > 
> > It looks like it belongs in the serial driver (and needs comments).
> 
> it configures the IOC3 chip for serial usage. This is not part of
> the serial register set, so it IMHO belongs in the MFD driver.

So it does serial things, but doesn't belong in the serial driver?

Could you please go into a bit more detail as to why you think that?

Why is it better here?

It's also totally unreadable by the way!

> > > +	}
> > > +#if defined(CONFIG_SGI_IP27)
> > 
> > What is this?  Can't you obtain this dynamically by probing the H/W?
> 
> that's the machine type and the #ifdef CONFIG_xxx are just for saving space,
> when compiled for other machines and it's easy to remove.

Please find other ways to save the space.  #ifery can get very messy,
very quickly and is almost always avoidable.

> > > +	if (ipd->info->irq_offset) {
> > 
> > What does this really signify?
> 
> IOC3 ASICs are most of the time connected to a SGI bridge chip. IOC3 can
> provide two interrupt lines, which are wired to the bridge chip. The first
> interrupt is assigned via the PCI core, but since IOC3 is not a PCI multi
> function device the second interrupt must be treated here. And the used
> interrupt line on the bridge chip differs between boards.

Please provide a MACRO, function or something else which results in
more readable code.  Whatever you choose to use, please add this text
above, it will be helpful for future readers.

> Thank you for your review. I'll address all other comments not cited in
> my mail.

NP

-- 
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/4] mfd: ioc3: Add driver for SGI IOC3 chip
  2019-05-08 10:23   ` Lee Jones
  2019-05-09 14:02     ` Thomas Bogendoerfer
@ 2019-05-14 12:39     ` Esben Haabendal
  1 sibling, 0 replies; 11+ messages in thread
From: Esben Haabendal @ 2019-05-14 12:39 UTC (permalink / raw)
  To: Thomas Bogendoerfer
  Cc: Lee Jones, Ralf Baechle, Paul Burton, James Hogan,
	Dmitry Torokhov, David S. Miller, Alessandro Zummo,
	Alexandre Belloni, Greg Kroah-Hartman, Jiri Slaby, linux-mips,
	linux-kernel, linux-input, netdev, linux-rtc, linux-serial

On Tue, 09 Apr 2019, Thomas Bogendoerfer wrote:
> 
> diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c
> index 358e66b81926..21fe722ebcd8 100644
> --- a/drivers/net/ethernet/sgi/ioc3-eth.c
> +++ b/drivers/net/ethernet/sgi/ioc3-eth.c
>  
>  [ ... ]
>  
> -	err = pci_request_regions(pdev, "ioc3");

Why are you dropping the call to pci_request_regions()?  Shouldn't you
do something similar in the new mfd driver?

When you are use the the BAR 0 resource as mem_base argument to
mfd_add_devices() later on, it will be split into child resources for
the child devices, but they will not be related to the IORESOURCE_MEM
root tree (iomem_resource) anymore.  I don't think that is how it is
supposed to be done, as it will allow random other drivers to request
the exact same memory area.

How/where is the memory resources inserted in the root IORESOURCE_MEM
resource (iomem_resource)?  Or is it allowed to use resources without
inserting it into the root tree?

> +	SET_NETDEV_DEV(dev, &pdev->dev);
> +	ip = netdev_priv(dev);
> +	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	ip->regs = ioremap(r->start, resource_size(r));
> +	r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	ip->ssram = ioremap(r->start, resource_size(r));

Maybe use devm_platform_ioremap_resource() instead, which handles both
platform_get_resource() and ioremap() in one call..

/Esben

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 2/4] mfd: ioc3: Add driver for SGI IOC3 chip
  2019-05-10  7:14       ` Lee Jones
@ 2019-05-14 14:29         ` Thomas Bogendoerfer
  0 siblings, 0 replies; 11+ messages in thread
From: Thomas Bogendoerfer @ 2019-05-14 14:29 UTC (permalink / raw)
  To: Lee Jones
  Cc: Ralf Baechle, Paul Burton, James Hogan, Dmitry Torokhov,
	David S. Miller, Alessandro Zummo, Alexandre Belloni,
	Greg Kroah-Hartman, Jiri Slaby, linux-mips, linux-kernel,
	linux-input, netdev, linux-rtc, linux-serial

On Fri, 10 May 2019 08:14:19 +0100
Lee Jones <lee.jones@linaro.org> wrote:

> On Thu, 09 May 2019, Thomas Bogendoerfer wrote:
> > > > +	}
> > > > +	pr_err("ioc3: CRC error in NIC address\n");
> > > > +}
> > > 
> > > This all looks like networking code.  If this is the case, it should
> > > be moved to drivers/networking or similar.
> > 
> > no it's not. nic stands for number in a can produced by Dallas Semi also
> > known under the name 1-Wire (https://en.wikipedia.org/wiki/1-Wire).
> > SGI used them to provide partnumber, serialnumber and mac addresses.
> > By placing the code to read the NiCs inside ioc3 driver there is no need
> > for locking and adding library code for accessing these informations.
> 
> Great.  So it looks like you should be using this, no?
> 
>   drivers/base/regmap/regmap-w1.c

not sure about regmap-w1, but drivers/w1 contains usefull stuff
like w1_crc8. The only drawback I see right now is, that I need
information about part numbers at ioc3 probe time, but for using
w1 framework I need to create a platform device, which will give
me this information not synchronous. I'll see how I could solve that.

> > > > +static struct resource ioc3_uarta_resources[] = {
> > > > +	DEFINE_RES_MEM(offsetof(struct ioc3, sregs.uarta),
> > > 
> > > You are the first user of offsetof() in MFD.  Could you tell me why
> > > it's required please?
> > 
> > to get the offsets of different chip functions out of a struct.
> 
> I can see what it does on a coding level.
> 
> What are you using it for in practical/real terms?

ioc3 has one PCI bar, where all different functions are accessible.
The current ioc3 register map has all these functions set up in one
struct. The base address of these registers comes out of the PCI
framework and to use the MFD framework I need offsets for the different
functions. And because there was already struct ioc3 I'm using
offsetof on this struct.

> Why wouldn't any other MFD driver require this, but you do?

the other PCI MFD drivers I've looked at, have a PCI BAR per function,
which makes live easier and no need for offsetof. Other MFD drivers
#define the offsets and don't have a big struct, which contains all
function registers. If you really insist on using #defines I need
to go through a few parts of the kernel where struct ioc3 is still used.

> > > > +	if (ipd->info->funcs & IOC3_SER) {
> > > > +		writel(GPCR_UARTA_MODESEL | GPCR_UARTB_MODESEL,
> > > > +			&ipd->regs->gpcr_s);
> > > > +		writel(0, &ipd->regs->gppr[6]);
> > > > +		writel(0, &ipd->regs->gppr[7]);
> > > > +		udelay(100);
> > > > +		writel(readl(&ipd->regs->port_a.sscr) & ~SSCR_DMA_EN,
> > > > +		       &ipd->regs->port_a.sscr);
> > > > +		writel(readl(&ipd->regs->port_b.sscr) & ~SSCR_DMA_EN,
> > > > +		       &ipd->regs->port_b.sscr);
> > > > +		udelay(1000);
> > > 
> > > No idea what any of this does.
> > > 
> > > It looks like it belongs in the serial driver (and needs comments).
> > 
> > it configures the IOC3 chip for serial usage. This is not part of
> > the serial register set, so it IMHO belongs in the MFD driver.
> 
> So it does serial things, but doesn't belong in the serial driver?

It sets up IOC3 GPIOs and IOC3 serial mode in way the 8250 driver
can work with the connected superio.

> Could you please go into a bit more detail as to why you think that?
> 
> Why is it better here?

access to gpio and serial mode is outside of the 8250 register space.
So either I need to export with some additional resources/new special
platform data or just set it where it is done.

> It's also totally unreadable by the way!

sure, I'll add comments.

> > > > +	}
> > > > +#if defined(CONFIG_SGI_IP27)
> > > 
> > > What is this?  Can't you obtain this dynamically by probing the H/W?
> > 
> > that's the machine type and the #ifdef CONFIG_xxx are just for saving space,
> > when compiled for other machines and it's easy to remove.
> 
> Please find other ways to save the space.  #ifery can get very messy,
> very quickly and is almost always avoidable.

space isn't a problem at all, so removing #ifdef CONFIG is easy.

> 
> > > > +	if (ipd->info->irq_offset) {
> > > 
> > > What does this really signify?
> > 
> > IOC3 ASICs are most of the time connected to a SGI bridge chip. IOC3 can
> > provide two interrupt lines, which are wired to the bridge chip. The first
> > interrupt is assigned via the PCI core, but since IOC3 is not a PCI multi
> > function device the second interrupt must be treated here. And the used
> > interrupt line on the bridge chip differs between boards.
> 
> Please provide a MACRO, function or something else which results in
> more readable code.  Whatever you choose to use, please add this text
> above, it will be helpful for future readers.

will do.

Thomas.

-- 
SUSE Linux GmbH
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah
HRB 21284 (AG Nürnberg)

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2019-05-14 14:29 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-09 15:46 [PATCH v2 0/4] Use MFD framework for SGI IOC3 drivers Thomas Bogendoerfer
2019-04-09 15:46 ` [PATCH v2 1/4] MIPS: SGI-IP27: remove ioc3 ethernet init Thomas Bogendoerfer
2019-04-09 15:46 ` [PATCH v2 3/4] MIPS: SGI-IP27: fix readb/writeb addressing Thomas Bogendoerfer
2019-04-11 21:17   ` Alexandre Belloni
2019-04-09 15:46 ` [PATCH v2 4/4] Input: add IOC3 serio driver Thomas Bogendoerfer
     [not found] ` <20190409154610.6735-3-tbogendoerfer@suse.de>
2019-04-16 13:16   ` [PATCH v2 2/4] mfd: ioc3: Add driver for SGI IOC3 chip Greg Kroah-Hartman
2019-05-08 10:23   ` Lee Jones
2019-05-09 14:02     ` Thomas Bogendoerfer
2019-05-10  7:14       ` Lee Jones
2019-05-14 14:29         ` Thomas Bogendoerfer
2019-05-14 12:39     ` Esben Haabendal

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).