aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/macintosh/via-pmu.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-10-05 09:55:46 -0400
committerDavid Howells <dhowells@warthog.cambridge.redhat.com>2006-10-05 10:10:12 -0400
commit7d12e780e003f93433d49ce78cfedf4b4c52adc5 (patch)
tree6748550400445c11a306b132009f3001e3525df8 /drivers/macintosh/via-pmu.c
parentda482792a6d1a3fbaaa25fae867b343fb4db3246 (diff)
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells <dhowells@redhat.com> (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
Diffstat (limited to 'drivers/macintosh/via-pmu.c')
-rw-r--r--drivers/macintosh/via-pmu.c32
1 files changed, 16 insertions, 16 deletions
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 4f04fd0956a0..e63ea1c1f3c1 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -191,8 +191,8 @@ static int pmu_adb_reset_bus(void);
191 191
192static int init_pmu(void); 192static int init_pmu(void);
193static void pmu_start(void); 193static void pmu_start(void);
194static irqreturn_t via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs); 194static irqreturn_t via_pmu_interrupt(int irq, void *arg);
195static irqreturn_t gpio1_interrupt(int irq, void *arg, struct pt_regs *regs); 195static irqreturn_t gpio1_interrupt(int irq, void *arg);
196static int proc_get_info(char *page, char **start, off_t off, 196static int proc_get_info(char *page, char **start, off_t off,
197 int count, int *eof, void *data); 197 int count, int *eof, void *data);
198static int proc_get_irqstats(char *page, char **start, off_t off, 198static int proc_get_irqstats(char *page, char **start, off_t off,
@@ -555,7 +555,7 @@ init_pmu(void)
555 } 555 }
556 if (pmu_state == idle) 556 if (pmu_state == idle)
557 adb_int_pending = 1; 557 adb_int_pending = 1;
558 via_pmu_interrupt(0, NULL, NULL); 558 via_pmu_interrupt(0, NULL);
559 udelay(10); 559 udelay(10);
560 } 560 }
561 561
@@ -1215,7 +1215,7 @@ pmu_poll(void)
1215 return; 1215 return;
1216 if (disable_poll) 1216 if (disable_poll)
1217 return; 1217 return;
1218 via_pmu_interrupt(0, NULL, NULL); 1218 via_pmu_interrupt(0, NULL);
1219} 1219}
1220 1220
1221void 1221void
@@ -1228,7 +1228,7 @@ pmu_poll_adb(void)
1228 /* Kicks ADB read when PMU is suspended */ 1228 /* Kicks ADB read when PMU is suspended */
1229 adb_int_pending = 1; 1229 adb_int_pending = 1;
1230 do { 1230 do {
1231 via_pmu_interrupt(0, NULL, NULL); 1231 via_pmu_interrupt(0, NULL);
1232 } while (pmu_suspended && (adb_int_pending || pmu_state != idle 1232 } while (pmu_suspended && (adb_int_pending || pmu_state != idle
1233 || req_awaiting_reply)); 1233 || req_awaiting_reply));
1234} 1234}
@@ -1239,7 +1239,7 @@ pmu_wait_complete(struct adb_request *req)
1239 if (!via) 1239 if (!via)
1240 return; 1240 return;
1241 while((pmu_state != idle && pmu_state != locked) || !req->complete) 1241 while((pmu_state != idle && pmu_state != locked) || !req->complete)
1242 via_pmu_interrupt(0, NULL, NULL); 1242 via_pmu_interrupt(0, NULL);
1243} 1243}
1244 1244
1245/* This function loops until the PMU is idle and prevents it from 1245/* This function loops until the PMU is idle and prevents it from
@@ -1268,7 +1268,7 @@ pmu_suspend(void)
1268 spin_unlock_irqrestore(&pmu_lock, flags); 1268 spin_unlock_irqrestore(&pmu_lock, flags);
1269 if (req_awaiting_reply) 1269 if (req_awaiting_reply)
1270 adb_int_pending = 1; 1270 adb_int_pending = 1;
1271 via_pmu_interrupt(0, NULL, NULL); 1271 via_pmu_interrupt(0, NULL);
1272 spin_lock_irqsave(&pmu_lock, flags); 1272 spin_lock_irqsave(&pmu_lock, flags);
1273 if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) { 1273 if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
1274#ifdef SUSPEND_USES_PMU 1274#ifdef SUSPEND_USES_PMU
@@ -1318,7 +1318,7 @@ pmu_resume(void)
1318 1318
1319/* Interrupt data could be the result data from an ADB cmd */ 1319/* Interrupt data could be the result data from an ADB cmd */
1320static void 1320static void
1321pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs) 1321pmu_handle_data(unsigned char *data, int len)
1322{ 1322{
1323 unsigned char ints, pirq; 1323 unsigned char ints, pirq;
1324 int i = 0; 1324 int i = 0;
@@ -1393,7 +1393,7 @@ next:
1393 if (!(pmu_kind == PMU_OHARE_BASED && len == 4 1393 if (!(pmu_kind == PMU_OHARE_BASED && len == 4
1394 && data[1] == 0x2c && data[3] == 0xff 1394 && data[1] == 0x2c && data[3] == 0xff
1395 && (data[2] & ~1) == 0xf4)) 1395 && (data[2] & ~1) == 0xf4))
1396 adb_input(data+1, len-1, regs, 1); 1396 adb_input(data+1, len-1, 1);
1397#endif /* CONFIG_ADB */ 1397#endif /* CONFIG_ADB */
1398 } 1398 }
1399 } 1399 }
@@ -1431,7 +1431,7 @@ next:
1431} 1431}
1432 1432
1433static struct adb_request* 1433static struct adb_request*
1434pmu_sr_intr(struct pt_regs *regs) 1434pmu_sr_intr(void)
1435{ 1435{
1436 struct adb_request *req; 1436 struct adb_request *req;
1437 int bite = 0; 1437 int bite = 0;
@@ -1537,7 +1537,7 @@ pmu_sr_intr(struct pt_regs *regs)
1537} 1537}
1538 1538
1539static irqreturn_t 1539static irqreturn_t
1540via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs) 1540via_pmu_interrupt(int irq, void *arg)
1541{ 1541{
1542 unsigned long flags; 1542 unsigned long flags;
1543 int intr; 1543 int intr;
@@ -1567,7 +1567,7 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
1567 pmu_irq_stats[0]++; 1567 pmu_irq_stats[0]++;
1568 } 1568 }
1569 if (intr & SR_INT) { 1569 if (intr & SR_INT) {
1570 req = pmu_sr_intr(regs); 1570 req = pmu_sr_intr();
1571 if (req) 1571 if (req)
1572 break; 1572 break;
1573 } 1573 }
@@ -1613,7 +1613,7 @@ no_free_slot:
1613 1613
1614 /* Deal with interrupt datas outside of the lock */ 1614 /* Deal with interrupt datas outside of the lock */
1615 if (int_data >= 0) { 1615 if (int_data >= 0) {
1616 pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data], regs); 1616 pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data]);
1617 spin_lock_irqsave(&pmu_lock, flags); 1617 spin_lock_irqsave(&pmu_lock, flags);
1618 ++disable_poll; 1618 ++disable_poll;
1619 int_data_state[int_data] = int_data_empty; 1619 int_data_state[int_data] = int_data_empty;
@@ -1638,7 +1638,7 @@ pmu_unlock(void)
1638 1638
1639 1639
1640static irqreturn_t 1640static irqreturn_t
1641gpio1_interrupt(int irq, void *arg, struct pt_regs *regs) 1641gpio1_interrupt(int irq, void *arg)
1642{ 1642{
1643 unsigned long flags; 1643 unsigned long flags;
1644 1644
@@ -1651,7 +1651,7 @@ gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
1651 pmu_irq_stats[1]++; 1651 pmu_irq_stats[1]++;
1652 adb_int_pending = 1; 1652 adb_int_pending = 1;
1653 spin_unlock_irqrestore(&pmu_lock, flags); 1653 spin_unlock_irqrestore(&pmu_lock, flags);
1654 via_pmu_interrupt(0, NULL, NULL); 1654 via_pmu_interrupt(0, NULL);
1655 return IRQ_HANDLED; 1655 return IRQ_HANDLED;
1656 } 1656 }
1657 return IRQ_NONE; 1657 return IRQ_NONE;
@@ -2116,7 +2116,7 @@ pmac_wakeup_devices(void)
2116 2116
2117 /* Force a poll of ADB interrupts */ 2117 /* Force a poll of ADB interrupts */
2118 adb_int_pending = 1; 2118 adb_int_pending = 1;
2119 via_pmu_interrupt(0, NULL, NULL); 2119 via_pmu_interrupt(0, NULL);
2120 2120
2121 /* Restart jiffies & scheduling */ 2121 /* Restart jiffies & scheduling */
2122 wakeup_decrementer(); 2122 wakeup_decrementer();