[PARPORT] Optimising parport access


Philip Blundell (Philip.Blundell@pobox.com)
Tue, 30 Dec 1997 18:44:28 +0000


Hi.

Some people have complained about the performance hit from using the parport
code to access hardware registers. Fortunately, it's quite easy to eliminate
this overhead in most cases, and the attached patch does this.

If you have selected exactly one lowlevel driver, and you answer no to
"foreign parallel hardware", then some extra optimisations will be enabled in
parport.h. Basically, this defines some macros so that calls to parport_*()
functions are mapped directly to the corresponding lowlevel driver's calls,
without having to go through the despatch table. Also, the lowlevel driver
can (and parport_pc does) make some of these inline functions, so avoiding any
function-call overhead at all.

The downside to all this is obviously that the compiled versions of your
high-level drivers become tied to one particular hardware type, so you can
only turn this on if you're sure you won't want another type of parallel port
(this is, obviously, not a big deal for most people).

Note that CONFIG_PARPORT_OTHER has no effect other than to defeat this
optimisation. If you have chosen support for more than one lowlevel driver
(either in the kernel or as a module) then the optimisation is disabled anyway.

David: with this in place, hopefully PPA can use the parport hardware access
functions rather than doing its own bashing on the bare metal. Keep the
assembler as an optional speedup if you want, but I'd very much like to see
the ability to have a "clean" version of ppa that would work on any type of
port.

I'll check all this in to the vger CVS tree this evening, and then make a new
patch against clean 2.1.76. I think the parport code is now basically
feature-complete for 2.2; we just need to fix the bugs. If anybody thinks
anything important is missing, this would be a good time to scream.

(Grant, is there anything else you'd need to have your paride drivers use
parport?)

p.

Index: Documentation/Configure.help
===================================================================
RCS file: /usr/local/repository/linux/Documentation/Configure.help,v
retrieving revision 1.7
diff -u -r1.7 Configure.help
--- Configure.help 1997/12/29 00:19:58 1.7
+++ Configure.help 1997/12/29 14:39:43
@@ -991,6 +991,12 @@
   Ultra/AX machines. This code is also available as a module (say M),
   called parport_ax.o. If in doubt, saying N is the safe plan.
 
+Foreign parallel hardware
+CONFIG_PARPORT_OTHER
+ Say Y here if you want to be able to load driver modules to support
+ other types of parallel port. This causes a performance loss, so most
+ people say N.
+
 Compile the kernel into the ELF object format
 CONFIG_ELF_KERNEL
   ELF (Executable and Linkable Format) is a format for libraries and
Index: arch/alpha/config.in
===================================================================
RCS file: /usr/local/repository/linux/arch/alpha/config.in,v
retrieving revision 1.5
diff -u -r1.5 config.in
--- config.in 1997/12/24 22:32:49 1.5
+++ config.in 1997/12/29 12:21:41
@@ -156,6 +156,9 @@
 tristate 'Parallel port support' CONFIG_PARPORT
 if [ "$CONFIG_PARPORT" != "n" ]; then
   dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+ if [ "$CONFIG_PARPORT_PC" != "n" ]; then
+ bool ' Support foreign hardware' CONFIG_PARPORT_OTHER
+ fi
 fi
 endmenu
 
Index: arch/i386/config.in
===================================================================
RCS file: /usr/local/repository/linux/arch/i386/config.in,v
retrieving revision 1.6
diff -u -r1.6 config.in
--- config.in 1997/12/24 22:32:54 1.6
+++ config.in 1997/12/29 12:21:25
@@ -57,6 +57,9 @@
 tristate 'Parallel port support' CONFIG_PARPORT
 if [ "$CONFIG_PARPORT" != "n" ]; then
   dep_tristate ' PC-style hardware' CONFIG_PARPORT_PC $CONFIG_PARPORT
+ if [ "$CONFIG_PARPORT_PC" != "n" ]; then
+ bool ' Support foreign hardware' CONFIG_PARPORT_OTHER
+ fi
 fi
 
 endmenu
Index: arch/sparc64/config.in
===================================================================
RCS file: /usr/local/repository/linux/arch/sparc64/config.in,v
retrieving revision 1.6
diff -u -r1.6 config.in
--- config.in 1997/12/24 22:34:22 1.6
+++ config.in 1997/12/29 12:22:23
@@ -75,6 +75,9 @@
   tristate 'Parallel port support' CONFIG_PARPORT
   if [ "$CONFIG_PARPORT" != "n" ]; then
     dep_tristate ' Ultra/AX-style hardware' CONFIG_PARPORT_AX $CONFIG_PARPORT
+ if [ "$CONFIG_PARPORT_AX" != "n" ]; then
+ bool ' Support foreign hardware' CONFIG_PARPORT_OTHER
+ fi
     dep_tristate ' Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
     if [ "$CONFIG_PRINTER" != "n" ]; then
       bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
Index: drivers/misc/parport_pc.c
===================================================================
RCS file: /usr/local/repository/linux/drivers/misc/parport_pc.c,v
retrieving revision 1.7
diff -u -r1.7 parport_pc.c
--- parport_pc.c 1997/12/24 22:37:32 1.7
+++ parport_pc.c 1997/12/29 12:36:34
@@ -64,8 +64,7 @@
 
 static void parport_pc_null_intr_func(int irq, void *dev_id, struct pt_regs *regs)
 {
- /* NULL function - Does nothing */
- return;
+ /* Null function - does nothing */
 }
 
 void parport_pc_write_epp(struct parport *p, unsigned int d)
Index: include/linux/parport.h
===================================================================
RCS file: /usr/local/repository/linux/include/linux/parport.h,v
retrieving revision 1.6
diff -u -r1.6 parport.h
--- parport.h 1997/12/29 12:31:05 1.6
+++ parport.h 1997/12/29 12:36:49
@@ -7,6 +7,29 @@
 #include <asm/ptrace.h>
 #include <linux/proc_fs.h>
 
+#define PARPORT_NEED_GENERIC_OPS
+
+/* If PC hardware is the only type supported, we can optimise a bit. */
+#if 0 && (defined(CONFIG_PARPORT_PC) || defined(CONFIG_PARPORT_PC_MODULE)) && !(defined(CONFIG_PARPORT_AX) || defined(CONFIG_PARPORT_AX_MODULE)) && !(defined(CONFIG_PARPORT_ARC) || defined(CONFIG_PARPORT_ARC_MODULE)) && !defined(CONFIG_PARPORT_OTHER)
+#undef PARPORT_NEED_GENERIC_OPS
+#include <linux/parport_pc.h>
+#define parport_write_data(p,x) parport_pc_write_data(p,x)
+#define parport_read_data(p) parport_pc_read_data(p)
+#define parport_write_control(p,x) parport_pc_write_control(p,x)
+#define parport_read_control(p) parport_pc_read_control(p)
+#define parport_frob_control(p,m,v) parport_pc_frob_control(p,m,v)
+#define parport_write_econtrol(p,x) parport_pc_write_econtrol(p,x)
+#define parport_read_econtrol(p) parport_pc_read_econtrol(p)
+#define parport_frob_econtrol(p,m,v) parport_pc_frob_econtrol(p,m,v)
+#define parport_write_status(p,v) parport_pc_write_status(p,v)
+#define parport_read_status(p) parport_pc_read_status(p)
+#define parport_write_fifo(p,v) parport_pc_write_fifo(p,v)
+#define parport_read_fifo(p) parport_pc_read_fifo(p)
+#define parport_change_mode(p,m) parport_pc_change_mode(p,m)
+#define parport_release_resources(p) parport_pc_release_resources(p)
+#define parport_claim_resources(p) parport_pc_claim_resources(p)
+#endif
+
 /* Maximum of 8 ports per machine */
 #define PARPORT_MAX 8
 
@@ -29,11 +52,12 @@
         union {
                 struct pc_parport_state pc;
                 /* ARC has no state. */
- /* AX uses sams state information as PC */
+ /* AX uses same state information as PC */
                 void *misc;
         } u;
 };
 
+#ifdef PARPORT_NEED_GENERIC_OPS
 /* Generic operations vector through the dispatch table. */
 #define parport_write_data(p,x) (p)->ops->write_data(p,x)
 #define parport_read_data(p) (p)->ops->read_data(p)
@@ -50,6 +74,7 @@
 #define parport_change_mode(p,m) (p)->ops->change_mode(p,m)
 #define parport_release_resources(p) (p)->ops->release_resources(p)
 #define parport_claim_resources(p) (p)->ops->claim_resources(p)
+#endif
 
 struct parport_operations {
         void (*write_data)(struct parport *, unsigned int);
--- /dev/null Tue Jan 1 04:00:00 1980
+++ include/linux/parport_pc.h Mon Dec 29 12:39:54 1997
@@ -0,0 +1,105 @@
+#ifndef __LINUX_PARPORT_PC_H
+#define __LINUX_PARPORT_PC_H
+
+extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned int d)
+{
+ outb(d, p->base+EPPREG);
+}
+
+extern __inline__ unsigned int parport_pc_read_epp(struct parport *p)
+{
+ return (unsigned int)inb(p->base+EPPREG);
+}
+
+extern __inline__ unsigned int parport_pc_read_configb(struct parport *p)
+{
+ return (unsigned int)inb(p->base+CONFIGB);
+}
+
+extern __inline__ void parport_pc_write_data(struct parport *p, unsigned int d)
+{
+ outb(d, p->base+DATA);
+}
+
+extern __inline__ unsigned int parport_pc_read_data(struct parport *p)
+{
+ return (unsigned int)inb(p->base+DATA);
+}
+
+extern __inline__ void parport_pc_write_control(struct parport *p, unsigned int d)
+{
+ outb(d, p->base+CONTROL);
+}
+
+extern __inline__ unsigned int parport_pc_read_control(struct parport *p)
+{
+ return (unsigned int)inb(p->base+CONTROL);
+}
+
+extern __inline__ unsigned int parport_pc_frob_control(struct parport *p, unsigned int mask, unsigned int val)
+{
+ unsigned int old = (unsigned int)inb(p->base+CONTROL);
+ outb(((old & ~mask) ^ val), p->base+CONTROL);
+ return old;
+}
+
+extern __inline__ void parport_pc_write_status(struct parport *p, unsigned int d)
+{
+ outb(d, p->base+STATUS);
+}
+
+extern __inline__ unsigned int parport_pc_read_status(struct parport *p)
+{
+ return (unsigned int)inb(p->base+STATUS);
+}
+
+extern __inline__ void parport_pc_write_econtrol(struct parport *p, unsigned int d)
+{
+ outb(d, p->base+ECONTROL);
+}
+
+extern __inline__ unsigned int parport_pc_read_econtrol(struct parport *p)
+{
+ return (unsigned int)inb(p->base+ECONTROL);
+}
+
+extern __inline__ unsigned int parport_pc_frob_econtrol(struct parport *p, unsigned int mask, unsigned int val)
+{
+ unsigned int old = (unsigned int)inb(p->base+ECONTROL);
+ outb(((old & ~mask) ^ val), p->base+ECONTROL);
+ return old;
+}
+
+extern void parport_pc_change_mode(struct parport *p, int m);
+
+extern void parport_pc_write_fifo(struct parport *p, unsigned int v);
+
+extern unsigned int parport_pc_read_fifo(struct parport *p);
+
+extern void parport_pc_disable_irq(struct parport *p);
+
+extern void parport_pc_enable_irq(struct parport *p);
+
+extern void parport_pc_release_resources(struct parport *p);
+
+extern int parport_pc_claim_resources(struct parport *p);
+
+extern void parport_pc_save_state(struct parport *p, struct parport_state *s);
+
+extern void parport_pc_restore_state(struct parport *p, struct parport_state *s);
+
+extern unsigned int parport_pc_epp_read_block(struct parport *p, void *buf, unsigned int length);
+
+extern unsigned int parport_pc_epp_write_block(struct parport *p, void *buf, unsigned int length);
+
+extern unsigned int parport_pc_ecp_read_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle);
+
+extern unsigned int parport_pc_ecp_write_block(struct parport *p, void *buf, unsigned int length, void (*fn)(struct parport *, void *, unsigned int), void *handle);
+
+extern int parport_pc_examine_irq(struct parport *p);
+
+extern void parport_pc_inc_use_count(void);
+
+extern void parport_pc_dec_use_count(void);
+
+#endif

-- To unsubscribe, send mail to: linux-parport-request@torque.net --
-- with the single word "unsubscribe" in the body of the message. --



This archive was generated by hypermail 2.0b3 on Wed 30 Dec 1998 - 10:17:16 EST