提交 3c241f83 编写于 作者: D Dmitry Torokhov
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
</authorgroup> </authorgroup>
<copyright> <copyright>
<year>2003</year> <year>2003-2005</year>
<holder>Jeff Garzik</holder> <holder>Jeff Garzik</holder>
</copyright> </copyright>
...@@ -44,30 +44,38 @@ ...@@ -44,30 +44,38 @@
<toc></toc> <toc></toc>
<chapter id="libataThanks"> <chapter id="libataIntroduction">
<title>Thanks</title> <title>Introduction</title>
<para> <para>
The bulk of the ATA knowledge comes thanks to long conversations with libATA is a library used inside the Linux kernel to support ATA host
Andre Hedrick (www.linux-ide.org). controllers and devices. libATA provides an ATA driver API, class
transports for ATA and ATAPI devices, and SCSI&lt;-&gt;ATA translation
for ATA devices according to the T10 SAT specification.
</para> </para>
<para> <para>
Thanks to Alan Cox for pointing out similarities This Guide documents the libATA driver API, library functions, library
between SATA and SCSI, and in general for motivation to hack on internals, and a couple sample ATA low-level drivers.
libata.
</para>
<para>
libata's device detection
method, ata_pio_devchk, and in general all the early probing was
based on extensive study of Hale Landis's probe/reset code in his
ATADRVR driver (www.ata-atapi.com).
</para> </para>
</chapter> </chapter>
<chapter id="libataDriverApi"> <chapter id="libataDriverApi">
<title>libata Driver API</title> <title>libata Driver API</title>
<para>
struct ata_port_operations is defined for every low-level libata
hardware driver, and it controls how the low-level driver
interfaces with the ATA and SCSI layers.
</para>
<para>
FIS-based drivers will hook into the system with ->qc_prep() and
->qc_issue() high-level hooks. Hardware which behaves in a manner
similar to PCI IDE hardware may utilize several generic helpers,
defining at a bare minimum the bus I/O addresses of the ATA shadow
register blocks.
</para>
<sect1> <sect1>
<title>struct ata_port_operations</title> <title>struct ata_port_operations</title>
<sect2><title>Disable ATA port</title>
<programlisting> <programlisting>
void (*port_disable) (struct ata_port *); void (*port_disable) (struct ata_port *);
</programlisting> </programlisting>
...@@ -78,6 +86,9 @@ void (*port_disable) (struct ata_port *); ...@@ -78,6 +86,9 @@ void (*port_disable) (struct ata_port *);
unplug). unplug).
</para> </para>
</sect2>
<sect2><title>Post-IDENTIFY device configuration</title>
<programlisting> <programlisting>
void (*dev_config) (struct ata_port *, struct ata_device *); void (*dev_config) (struct ata_port *, struct ata_device *);
</programlisting> </programlisting>
...@@ -88,6 +99,9 @@ void (*dev_config) (struct ata_port *, struct ata_device *); ...@@ -88,6 +99,9 @@ void (*dev_config) (struct ata_port *, struct ata_device *);
issue of SET FEATURES - XFER MODE, and prior to operation. issue of SET FEATURES - XFER MODE, and prior to operation.
</para> </para>
</sect2>
<sect2><title>Set PIO/DMA mode</title>
<programlisting> <programlisting>
void (*set_piomode) (struct ata_port *, struct ata_device *); void (*set_piomode) (struct ata_port *, struct ata_device *);
void (*set_dmamode) (struct ata_port *, struct ata_device *); void (*set_dmamode) (struct ata_port *, struct ata_device *);
...@@ -108,6 +122,9 @@ void (*post_set_mode) (struct ata_port *ap); ...@@ -108,6 +122,9 @@ void (*post_set_mode) (struct ata_port *ap);
->set_dma_mode() is only called if DMA is possible. ->set_dma_mode() is only called if DMA is possible.
</para> </para>
</sect2>
<sect2><title>Taskfile read/write</title>
<programlisting> <programlisting>
void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf); void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf);
void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf); void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
...@@ -120,6 +137,9 @@ void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf); ...@@ -120,6 +137,9 @@ void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
taskfile register values. taskfile register values.
</para> </para>
</sect2>
<sect2><title>ATA command execute</title>
<programlisting> <programlisting>
void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf); void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
</programlisting> </programlisting>
...@@ -129,17 +149,37 @@ void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf); ...@@ -129,17 +149,37 @@ void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
->tf_load(), to be initiated in hardware. ->tf_load(), to be initiated in hardware.
</para> </para>
</sect2>
<sect2><title>Per-cmd ATAPI DMA capabilities filter</title>
<programlisting>
int (*check_atapi_dma) (struct ata_queued_cmd *qc);
</programlisting>
<para>
Allow low-level driver to filter ATA PACKET commands, returning a status
indicating whether or not it is OK to use DMA for the supplied PACKET
command.
</para>
</sect2>
<sect2><title>Read specific ATA shadow registers</title>
<programlisting> <programlisting>
u8 (*check_status)(struct ata_port *ap); u8 (*check_status)(struct ata_port *ap);
void (*dev_select)(struct ata_port *ap, unsigned int device); u8 (*check_altstatus)(struct ata_port *ap);
u8 (*check_err)(struct ata_port *ap);
</programlisting> </programlisting>
<para> <para>
Reads the Status ATA shadow register from hardware. On some Reads the Status/AltStatus/Error ATA shadow register from
hardware, this has the side effect of clearing the interrupt hardware. On some hardware, reading the Status register has
condition. the side effect of clearing the interrupt condition.
</para> </para>
</sect2>
<sect2><title>Select ATA device on bus</title>
<programlisting> <programlisting>
void (*dev_select)(struct ata_port *ap, unsigned int device); void (*dev_select)(struct ata_port *ap, unsigned int device);
</programlisting> </programlisting>
...@@ -147,9 +187,13 @@ void (*dev_select)(struct ata_port *ap, unsigned int device); ...@@ -147,9 +187,13 @@ void (*dev_select)(struct ata_port *ap, unsigned int device);
<para> <para>
Issues the low-level hardware command(s) that causes one of N Issues the low-level hardware command(s) that causes one of N
hardware devices to be considered 'selected' (active and hardware devices to be considered 'selected' (active and
available for use) on the ATA bus. available for use) on the ATA bus. This generally has no
meaning on FIS-based devices.
</para> </para>
</sect2>
<sect2><title>Reset ATA bus</title>
<programlisting> <programlisting>
void (*phy_reset) (struct ata_port *ap); void (*phy_reset) (struct ata_port *ap);
</programlisting> </programlisting>
...@@ -162,17 +206,31 @@ void (*phy_reset) (struct ata_port *ap); ...@@ -162,17 +206,31 @@ void (*phy_reset) (struct ata_port *ap);
functions ata_bus_reset() or sata_phy_reset() for this hook. functions ata_bus_reset() or sata_phy_reset() for this hook.
</para> </para>
</sect2>
<sect2><title>Control PCI IDE BMDMA engine</title>
<programlisting> <programlisting>
void (*bmdma_setup) (struct ata_queued_cmd *qc); void (*bmdma_setup) (struct ata_queued_cmd *qc);
void (*bmdma_start) (struct ata_queued_cmd *qc); void (*bmdma_start) (struct ata_queued_cmd *qc);
void (*bmdma_stop) (struct ata_port *ap);
u8 (*bmdma_status) (struct ata_port *ap);
</programlisting> </programlisting>
<para> <para>
When setting up an IDE BMDMA transaction, these hooks arm When setting up an IDE BMDMA transaction, these hooks arm
(->bmdma_setup) and fire (->bmdma_start) the hardware's DMA (->bmdma_setup), fire (->bmdma_start), and halt (->bmdma_stop)
engine. the hardware's DMA engine. ->bmdma_status is used to read the standard
PCI IDE DMA Status register.
</para> </para>
<para>
These hooks are typically either no-ops, or simply not implemented, in
FIS-based drivers.
</para>
</sect2>
<sect2><title>High-level taskfile hooks</title>
<programlisting> <programlisting>
void (*qc_prep) (struct ata_queued_cmd *qc); void (*qc_prep) (struct ata_queued_cmd *qc);
int (*qc_issue) (struct ata_queued_cmd *qc); int (*qc_issue) (struct ata_queued_cmd *qc);
...@@ -190,20 +248,26 @@ int (*qc_issue) (struct ata_queued_cmd *qc); ...@@ -190,20 +248,26 @@ int (*qc_issue) (struct ata_queued_cmd *qc);
->qc_issue is used to make a command active, once the hardware ->qc_issue is used to make a command active, once the hardware
and S/G tables have been prepared. IDE BMDMA drivers use the and S/G tables have been prepared. IDE BMDMA drivers use the
helper function ata_qc_issue_prot() for taskfile protocol-based helper function ata_qc_issue_prot() for taskfile protocol-based
dispatch. More advanced drivers roll their own ->qc_issue dispatch. More advanced drivers implement their own ->qc_issue.
implementation, using this as the "issue new ATA command to
hardware" hook.
</para> </para>
</sect2>
<sect2><title>Timeout (error) handling</title>
<programlisting> <programlisting>
void (*eng_timeout) (struct ata_port *ap); void (*eng_timeout) (struct ata_port *ap);
</programlisting> </programlisting>
<para> <para>
This is a high level error handling function, called from the This is a high level error handling function, called from the
error handling thread, when a command times out. error handling thread, when a command times out. Most newer
hardware will implement its own error handling code here. IDE BMDMA
drivers may use the helper function ata_eng_timeout().
</para> </para>
</sect2>
<sect2><title>Hardware interrupt handling</title>
<programlisting> <programlisting>
irqreturn_t (*irq_handler)(int, void *, struct pt_regs *); irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
void (*irq_clear) (struct ata_port *); void (*irq_clear) (struct ata_port *);
...@@ -216,6 +280,9 @@ void (*irq_clear) (struct ata_port *); ...@@ -216,6 +280,9 @@ void (*irq_clear) (struct ata_port *);
is quiet. is quiet.
</para> </para>
</sect2>
<sect2><title>SATA phy read/write</title>
<programlisting> <programlisting>
u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg); u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
void (*scr_write) (struct ata_port *ap, unsigned int sc_reg, void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
...@@ -227,6 +294,9 @@ void (*scr_write) (struct ata_port *ap, unsigned int sc_reg, ...@@ -227,6 +294,9 @@ void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
if ->phy_reset hook called the sata_phy_reset() helper function. if ->phy_reset hook called the sata_phy_reset() helper function.
</para> </para>
</sect2>
<sect2><title>Init and shutdown</title>
<programlisting> <programlisting>
int (*port_start) (struct ata_port *ap); int (*port_start) (struct ata_port *ap);
void (*port_stop) (struct ata_port *ap); void (*port_stop) (struct ata_port *ap);
...@@ -240,15 +310,17 @@ void (*host_stop) (struct ata_host_set *host_set); ...@@ -240,15 +310,17 @@ void (*host_stop) (struct ata_host_set *host_set);
tasks. tasks.
</para> </para>
<para> <para>
->host_stop() is called when the rmmod or hot unplug process
begins. The hook must stop all hardware interrupts, DMA
engines, etc.
</para>
<para>
->port_stop() is called after ->host_stop(). It's sole function ->port_stop() is called after ->host_stop(). It's sole function
is to release DMA/memory resources, now that they are no longer is to release DMA/memory resources, now that they are no longer
actively being used. actively being used.
</para> </para>
<para>
->host_stop() is called after all ->port_stop() calls
have completed. The hook must finalize hardware shutdown, release DMA
and other resources, etc.
</para>
</sect2>
</sect1> </sect1>
</chapter> </chapter>
...@@ -279,4 +351,24 @@ void (*host_stop) (struct ata_host_set *host_set); ...@@ -279,4 +351,24 @@ void (*host_stop) (struct ata_host_set *host_set);
!Idrivers/scsi/sata_sil.c !Idrivers/scsi/sata_sil.c
</chapter> </chapter>
<chapter id="libataThanks">
<title>Thanks</title>
<para>
The bulk of the ATA knowledge comes thanks to long conversations with
Andre Hedrick (www.linux-ide.org), and long hours pondering the ATA
and SCSI specifications.
</para>
<para>
Thanks to Alan Cox for pointing out similarities
between SATA and SCSI, and in general for motivation to hack on
libata.
</para>
<para>
libata's device detection
method, ata_pio_devchk, and in general all the early probing was
based on extensive study of Hale Landis's probe/reset code in his
ATADRVR driver (www.ata-atapi.com).
</para>
</chapter>
</book> </book>
...@@ -239,6 +239,12 @@ L: linux-usb-devel@lists.sourceforge.net ...@@ -239,6 +239,12 @@ L: linux-usb-devel@lists.sourceforge.net
W: http://www.linux-usb.org/SpeedTouch/ W: http://www.linux-usb.org/SpeedTouch/
S: Maintained S: Maintained
ALI1563 I2C DRIVER
P: Rudolf Marek
M: r.marek@sh.cvut.cz
L: sensors@stimpy.netroedge.com
S: Maintained
ALPHA PORT ALPHA PORT
P: Richard Henderson P: Richard Henderson
M: rth@twiddle.net M: rth@twiddle.net
......
...@@ -2427,7 +2427,7 @@ sys32_epoll_wait(int epfd, struct epoll_event32 __user * events, int maxevents, ...@@ -2427,7 +2427,7 @@ sys32_epoll_wait(int epfd, struct epoll_event32 __user * events, int maxevents,
{ {
struct epoll_event *events64 = NULL; struct epoll_event *events64 = NULL;
mm_segment_t old_fs = get_fs(); mm_segment_t old_fs = get_fs();
int error, numevents, size; int numevents, size;
int evt_idx; int evt_idx;
int do_free_pages = 0; int do_free_pages = 0;
......
...@@ -1103,8 +1103,6 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs) ...@@ -1103,8 +1103,6 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#endif /* CONFIG_ACPI */
/* /*
* ia64_mca_cpe_poll * ia64_mca_cpe_poll
* *
...@@ -1122,6 +1120,8 @@ ia64_mca_cpe_poll (unsigned long dummy) ...@@ -1122,6 +1120,8 @@ ia64_mca_cpe_poll (unsigned long dummy)
platform_send_ipi(first_cpu(cpu_online_map), IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0); platform_send_ipi(first_cpu(cpu_online_map), IA64_CPEP_VECTOR, IA64_IPI_DM_INT, 0);
} }
#endif /* CONFIG_ACPI */
/* /*
* C portion of the OS INIT handler * C portion of the OS INIT handler
* *
......
...@@ -45,11 +45,13 @@ asmlinkage void ret_from_fork(void); ...@@ -45,11 +45,13 @@ asmlinkage void ret_from_fork(void);
*/ */
void default_idle(void) void default_idle(void)
{ {
while(1) { local_irq_disable();
if (need_resched()) while (!need_resched()) {
__asm__("stop #0x2000" : : : "cc"); /* This stop will re-enable interrupts */
schedule(); __asm__("stop #0x2000" : : : "cc");
local_irq_disable();
} }
local_irq_enable();
} }
void (*idle)(void) = default_idle; void (*idle)(void) = default_idle;
...@@ -63,7 +65,12 @@ void (*idle)(void) = default_idle; ...@@ -63,7 +65,12 @@ void (*idle)(void) = default_idle;
void cpu_idle(void) void cpu_idle(void)
{ {
/* endless idle loop with no priority at all */ /* endless idle loop with no priority at all */
idle(); while (1) {
idle();
preempt_enable_no_resched();
schedule();
preempt_disable();
}
} }
void machine_restart(char * __unused) void machine_restart(char * __unused)
......
...@@ -626,8 +626,18 @@ inspect_node(phandle node, struct device_node *dad, ...@@ -626,8 +626,18 @@ inspect_node(phandle node, struct device_node *dad,
l = call_prom("package-to-path", 3, 1, node, l = call_prom("package-to-path", 3, 1, node,
mem_start, mem_end - mem_start); mem_start, mem_end - mem_start);
if (l >= 0) { if (l >= 0) {
char *p, *ep;
np->full_name = PTRUNRELOC((char *) mem_start); np->full_name = PTRUNRELOC((char *) mem_start);
*(char *)(mem_start + l) = 0; *(char *)(mem_start + l) = 0;
/* Fixup an Apple bug where they have bogus \0 chars in the
* middle of the path in some properties
*/
for (p = (char *)mem_start, ep = p + l; p < ep; p++)
if ((*p) == '\0') {
memmove(p, p+1, ep - p);
ep--;
}
mem_start = ALIGNUL(mem_start + l + 1); mem_start = ALIGNUL(mem_start + l + 1);
} }
......
...@@ -436,15 +436,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) ...@@ -436,15 +436,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
REST_8GPRS(14, r1) REST_8GPRS(14, r1)
REST_10GPRS(22, r1) REST_10GPRS(22, r1)
#ifdef CONFIG_PPC_ISERIES
clrrdi r7,r1,THREAD_SHIFT /* get current_thread_info() */
ld r7,TI_FLAGS(r7) /* Get run light flag */
mfspr r9,CTRLF
srdi r7,r7,TIF_RUN_LIGHT
insrdi r9,r7,1,63 /* Insert run light into CTRL */
mtspr CTRLT,r9
#endif
/* convert old thread to its task_struct for return value */ /* convert old thread to its task_struct for return value */
addi r3,r3,-THREAD addi r3,r3,-THREAD
ld r7,_NIP(r1) /* Return to _switch caller in new task */ ld r7,_NIP(r1) /* Return to _switch caller in new task */
......
...@@ -626,10 +626,10 @@ system_reset_iSeries: ...@@ -626,10 +626,10 @@ system_reset_iSeries:
lhz r24,PACAPACAINDEX(r13) /* Get processor # */ lhz r24,PACAPACAINDEX(r13) /* Get processor # */
cmpwi 0,r24,0 /* Are we processor 0? */ cmpwi 0,r24,0 /* Are we processor 0? */
beq .__start_initialization_iSeries /* Start up the first processor */ beq .__start_initialization_iSeries /* Start up the first processor */
mfspr r4,CTRLF mfspr r4,SPRN_CTRLF
li r5,RUNLATCH /* Turn off the run light */ li r5,CTRL_RUNLATCH /* Turn off the run light */
andc r4,r4,r5 andc r4,r4,r5
mtspr CTRLT,r4 mtspr SPRN_CTRLT,r4
1: 1:
HMT_LOW HMT_LOW
...@@ -2082,9 +2082,9 @@ _GLOBAL(hmt_start_secondary) ...@@ -2082,9 +2082,9 @@ _GLOBAL(hmt_start_secondary)
mfspr r4, HID0 mfspr r4, HID0
ori r4, r4, 0x1 ori r4, r4, 0x1
mtspr HID0, r4 mtspr HID0, r4
mfspr r4, CTRLF mfspr r4, SPRN_CTRLF
oris r4, r4, 0x40 oris r4, r4, 0x40
mtspr CTRLT, r4 mtspr SPRN_CTRLT, r4
blr blr
#endif #endif
......
...@@ -852,6 +852,28 @@ static int __init iSeries_src_init(void) ...@@ -852,6 +852,28 @@ static int __init iSeries_src_init(void)
late_initcall(iSeries_src_init); late_initcall(iSeries_src_init);
static int set_spread_lpevents(char *str)
{
unsigned long i;
unsigned long val = simple_strtoul(str, NULL, 0);
/*
* The parameter is the number of processors to share in processing
* lp events.
*/
if (( val > 0) && (val <= NR_CPUS)) {
for (i = 1; i < val; ++i)
paca[i].lpqueue_ptr = paca[0].lpqueue_ptr;
printk("lpevent processing spread over %ld processors\n", val);
} else {
printk("invalid spread_lpevents %ld\n", val);
}
return 1;
}
__setup("spread_lpevents=", set_spread_lpevents);
void __init iSeries_early_setup(void) void __init iSeries_early_setup(void)
{ {
iSeries_fixup_klimit(); iSeries_fixup_klimit();
......
...@@ -75,13 +75,9 @@ static int iSeries_idle(void) ...@@ -75,13 +75,9 @@ static int iSeries_idle(void)
{ {
struct paca_struct *lpaca; struct paca_struct *lpaca;
long oldval; long oldval;
unsigned long CTRL;
/* ensure iSeries run light will be out when idle */ /* ensure iSeries run light will be out when idle */
clear_thread_flag(TIF_RUN_LIGHT); ppc64_runlatch_off();
CTRL = mfspr(CTRLF);
CTRL &= ~RUNLATCH;
mtspr(CTRLT, CTRL);
lpaca = get_paca(); lpaca = get_paca();
...@@ -111,7 +107,9 @@ static int iSeries_idle(void) ...@@ -111,7 +107,9 @@ static int iSeries_idle(void)
} }
} }
ppc64_runlatch_on();
schedule(); schedule();
ppc64_runlatch_off();
} }
return 0; return 0;
......
...@@ -47,14 +47,6 @@ static void remove_node_proc_entries(struct device_node *np) ...@@ -47,14 +47,6 @@ static void remove_node_proc_entries(struct device_node *np)
remove_proc_entry(pp->name, np->pde); remove_proc_entry(pp->name, np->pde);
pp = pp->next; pp = pp->next;
} }
/* Assuming that symlinks have the same parent directory as
* np->pde.
*/
if (np->name_link)
remove_proc_entry(np->name_link->name, parent->pde);
if (np->addr_link)
remove_proc_entry(np->addr_link->name, parent->pde);
if (np->pde) if (np->pde)
remove_proc_entry(np->pde->name, parent->pde); remove_proc_entry(np->pde->name, parent->pde);
} }
......
...@@ -378,9 +378,6 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp, ...@@ -378,9 +378,6 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
childregs->gpr[1] = sp + sizeof(struct pt_regs); childregs->gpr[1] = sp + sizeof(struct pt_regs);
p->thread.regs = NULL; /* no user register state */ p->thread.regs = NULL; /* no user register state */
clear_ti_thread_flag(p->thread_info, TIF_32BIT); clear_ti_thread_flag(p->thread_info, TIF_32BIT);
#ifdef CONFIG_PPC_ISERIES
set_ti_thread_flag(p->thread_info, TIF_RUN_LIGHT);
#endif
} else { } else {
childregs->gpr[1] = usp; childregs->gpr[1] = usp;
p->thread.regs = childregs; p->thread.regs = childregs;
......
...@@ -211,13 +211,23 @@ struct { ...@@ -211,13 +211,23 @@ struct {
*/ */
#define ADDR(x) (u32) ((unsigned long)(x) - offset) #define ADDR(x) (u32) ((unsigned long)(x) - offset)
/*
* Error results ... some OF calls will return "-1" on error, some
* will return 0, some will return either. To simplify, here are
* macros to use with any ihandle or phandle return value to check if
* it is valid
*/
#define PROM_ERROR (-1u)
#define PHANDLE_VALID(p) ((p) != 0 && (p) != PROM_ERROR)
#define IHANDLE_VALID(i) ((i) != 0 && (i) != PROM_ERROR)
/* This is the one and *ONLY* place where we actually call open /* This is the one and *ONLY* place where we actually call open
* firmware from, since we need to make sure we're running in 32b * firmware from, since we need to make sure we're running in 32b
* mode when we do. We switch back to 64b mode upon return. * mode when we do. We switch back to 64b mode upon return.
*/ */
#define PROM_ERROR (-1)
static int __init call_prom(const char *service, int nargs, int nret, ...) static int __init call_prom(const char *service, int nargs, int nret, ...)
{ {
int i; int i;
...@@ -587,14 +597,13 @@ static void __init prom_send_capabilities(void) ...@@ -587,14 +597,13 @@ static void __init prom_send_capabilities(void)
{ {
unsigned long offset = reloc_offset(); unsigned long offset = reloc_offset();
ihandle elfloader; ihandle elfloader;
int ret;
elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader")); elfloader = call_prom("open", 1, 1, ADDR("/packages/elf-loader"));
if (elfloader == 0) { if (elfloader == 0) {
prom_printf("couldn't open /packages/elf-loader\n"); prom_printf("couldn't open /packages/elf-loader\n");
return; return;
} }
ret = call_prom("call-method", 3, 1, ADDR("process-elf-header"), call_prom("call-method", 3, 1, ADDR("process-elf-header"),
elfloader, ADDR(&fake_elf)); elfloader, ADDR(&fake_elf));
call_prom("close", 1, 0, elfloader); call_prom("close", 1, 0, elfloader);
} }
...@@ -646,7 +655,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align) ...@@ -646,7 +655,7 @@ static unsigned long __init alloc_up(unsigned long size, unsigned long align)
base = _ALIGN_UP(base + 0x100000, align)) { base = _ALIGN_UP(base + 0x100000, align)) {
prom_debug(" trying: 0x%x\n\r", base); prom_debug(" trying: 0x%x\n\r", base);
addr = (unsigned long)prom_claim(base, size, 0); addr = (unsigned long)prom_claim(base, size, 0);
if ((int)addr != PROM_ERROR) if (addr != PROM_ERROR)
break; break;
addr = 0; addr = 0;
if (align == 0) if (align == 0)
...@@ -708,7 +717,7 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align, ...@@ -708,7 +717,7 @@ static unsigned long __init alloc_down(unsigned long size, unsigned long align,
for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align)) { for(; base > RELOC(alloc_bottom); base = _ALIGN_DOWN(base - 0x100000, align)) {
prom_debug(" trying: 0x%x\n\r", base); prom_debug(" trying: 0x%x\n\r", base);
addr = (unsigned long)prom_claim(base, size, 0); addr = (unsigned long)prom_claim(base, size, 0);
if ((int)addr != PROM_ERROR) if (addr != PROM_ERROR)
break; break;
addr = 0; addr = 0;
} }
...@@ -902,18 +911,19 @@ static void __init prom_instantiate_rtas(void) ...@@ -902,18 +911,19 @@ static void __init prom_instantiate_rtas(void)
{ {
unsigned long offset = reloc_offset(); unsigned long offset = reloc_offset();
struct prom_t *_prom = PTRRELOC(&prom); struct prom_t *_prom = PTRRELOC(&prom);
phandle prom_rtas, rtas_node; phandle rtas_node;
ihandle rtas_inst;
u32 base, entry = 0; u32 base, entry = 0;
u32 size = 0; u32 size = 0;
prom_debug("prom_instantiate_rtas: start...\n"); prom_debug("prom_instantiate_rtas: start...\n");
prom_rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); rtas_node = call_prom("finddevice", 1, 1, ADDR("/rtas"));
prom_debug("prom_rtas: %x\n", prom_rtas); prom_debug("rtas_node: %x\n", rtas_node);
if (prom_rtas == (phandle) -1) if (!PHANDLE_VALID(rtas_node))
return; return;
prom_getprop(prom_rtas, "rtas-size", &size, sizeof(size)); prom_getprop(rtas_node, "rtas-size", &size, sizeof(size));
if (size == 0) if (size == 0)
return; return;
...@@ -922,14 +932,18 @@ static void __init prom_instantiate_rtas(void) ...@@ -922,14 +932,18 @@ static void __init prom_instantiate_rtas(void)
prom_printf("RTAS allocation failed !\n"); prom_printf("RTAS allocation failed !\n");
return; return;
} }
prom_printf("instantiating rtas at 0x%x", base);
rtas_node = call_prom("open", 1, 1, ADDR("/rtas")); rtas_inst = call_prom("open", 1, 1, ADDR("/rtas"));
prom_printf("..."); if (!IHANDLE_VALID(rtas_inst)) {
prom_printf("opening rtas package failed");
return;
}
prom_printf("instantiating rtas at 0x%x ...", base);
if (call_prom("call-method", 3, 2, if (call_prom("call-method", 3, 2,
ADDR("instantiate-rtas"), ADDR("instantiate-rtas"),
rtas_node, base) != PROM_ERROR) { rtas_inst, base) != PROM_ERROR) {
entry = (long)_prom->args.rets[1]; entry = (long)_prom->args.rets[1];
} }
if (entry == 0) { if (entry == 0) {
...@@ -940,8 +954,8 @@ static void __init prom_instantiate_rtas(void) ...@@ -940,8 +954,8 @@ static void __init prom_instantiate_rtas(void)
reserve_mem(base, size); reserve_mem(base, size);
prom_setprop(prom_rtas, "linux,rtas-base", &base, sizeof(base)); prom_setprop(rtas_node, "linux,rtas-base", &base, sizeof(base));
prom_setprop(prom_rtas, "linux,rtas-entry", &entry, sizeof(entry)); prom_setprop(rtas_node, "linux,rtas-entry", &entry, sizeof(entry));
prom_debug("rtas base = 0x%x\n", base); prom_debug("rtas base = 0x%x\n", base);
prom_debug("rtas entry = 0x%x\n", entry); prom_debug("rtas entry = 0x%x\n", entry);
...@@ -1062,7 +1076,7 @@ static void __init prom_initialize_tce_table(void) ...@@ -1062,7 +1076,7 @@ static void __init prom_initialize_tce_table(void)
prom_printf("opening PHB %s", path); prom_printf("opening PHB %s", path);
phb_node = call_prom("open", 1, 1, path); phb_node = call_prom("open", 1, 1, path);
if ( (long)phb_node <= 0) if (phb_node == 0)
prom_printf("... failed\n"); prom_printf("... failed\n");
else else
prom_printf("... done\n"); prom_printf("... done\n");
...@@ -1279,12 +1293,12 @@ static void __init prom_init_client_services(unsigned long pp) ...@@ -1279,12 +1293,12 @@ static void __init prom_init_client_services(unsigned long pp)
/* get a handle for the stdout device */ /* get a handle for the stdout device */
_prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen")); _prom->chosen = call_prom("finddevice", 1, 1, ADDR("/chosen"));
if ((long)_prom->chosen <= 0) if (!PHANDLE_VALID(_prom->chosen))
prom_panic("cannot find chosen"); /* msg won't be printed :( */ prom_panic("cannot find chosen"); /* msg won't be printed :( */
/* get device tree root */ /* get device tree root */
_prom->root = call_prom("finddevice", 1, 1, ADDR("/")); _prom->root = call_prom("finddevice", 1, 1, ADDR("/"));
if ((long)_prom->root <= 0) if (!PHANDLE_VALID(_prom->root))
prom_panic("cannot find device tree root"); /* msg won't be printed :( */ prom_panic("cannot find device tree root"); /* msg won't be printed :( */
} }
...@@ -1356,9 +1370,8 @@ static int __init prom_find_machine_type(void) ...@@ -1356,9 +1370,8 @@ static int __init prom_find_machine_type(void)
} }
/* Default to pSeries. We need to know if we are running LPAR */ /* Default to pSeries. We need to know if we are running LPAR */
rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
if (rtas != (phandle) -1) { if (PHANDLE_VALID(rtas)) {
unsigned long x; int x = prom_getproplen(rtas, "ibm,hypertas-functions");
x = prom_getproplen(rtas, "ibm,hypertas-functions");
if (x != PROM_ERROR) { if (x != PROM_ERROR) {
prom_printf("Hypertas detected, assuming LPAR !\n"); prom_printf("Hypertas detected, assuming LPAR !\n");
return PLATFORM_PSERIES_LPAR; return PLATFORM_PSERIES_LPAR;
...@@ -1426,12 +1439,13 @@ static void __init prom_check_displays(void) ...@@ -1426,12 +1439,13 @@ static void __init prom_check_displays(void)
* leave some room at the end of the path for appending extra * leave some room at the end of the path for appending extra
* arguments * arguments
*/ */
if (call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-10) < 0) if (call_prom("package-to-path", 3, 1, node, path,
PROM_SCRATCH_SIZE-10) == PROM_ERROR)
continue; continue;
prom_printf("found display : %s, opening ... ", path); prom_printf("found display : %s, opening ... ", path);
ih = call_prom("open", 1, 1, path); ih = call_prom("open", 1, 1, path);
if (ih == (ihandle)0 || ih == (ihandle)-1) { if (ih == 0) {
prom_printf("failed\n"); prom_printf("failed\n");
continue; continue;
} }
...@@ -1514,6 +1528,12 @@ static unsigned long __init dt_find_string(char *str) ...@@ -1514,6 +1528,12 @@ static unsigned long __init dt_find_string(char *str)
return 0; return 0;
} }
/*
* The Open Firmware 1275 specification states properties must be 31 bytes or
* less, however not all firmwares obey this. Make it 64 bytes to be safe.
*/
#define MAX_PROPERTY_NAME 64
static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
unsigned long *mem_end) unsigned long *mem_end)
{ {
...@@ -1527,10 +1547,12 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, ...@@ -1527,10 +1547,12 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
/* get and store all property names */ /* get and store all property names */
prev_name = RELOC(""); prev_name = RELOC("");
for (;;) { for (;;) {
int rc;
/* 32 is max len of name including nul. */
namep = make_room(mem_start, mem_end, 32, 1); /* 64 is max len of name including nul. */
if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0) { namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1);
rc = call_prom("nextprop", 3, 1, node, prev_name, namep);
if (rc != 1) {
/* No more nodes: unwind alloc */ /* No more nodes: unwind alloc */
*mem_start = (unsigned long)namep; *mem_start = (unsigned long)namep;
break; break;
...@@ -1555,18 +1577,12 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, ...@@ -1555,18 +1577,12 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start,
} }
} }
/*
* The Open Firmware 1275 specification states properties must be 31 bytes or
* less, however not all firmwares obey this. Make it 64 bytes to be safe.
*/
#define MAX_PROPERTY_NAME 64
static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
unsigned long *mem_end) unsigned long *mem_end)
{ {
int l, align; int l, align;
phandle child; phandle child;
char *namep, *prev_name, *sstart; char *namep, *prev_name, *sstart, *p, *ep;
unsigned long soff; unsigned long soff;
unsigned char *valp; unsigned char *valp;
unsigned long offset = reloc_offset(); unsigned long offset = reloc_offset();
...@@ -1588,6 +1604,14 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, ...@@ -1588,6 +1604,14 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
call_prom("package-to-path", 3, 1, node, namep, l); call_prom("package-to-path", 3, 1, node, namep, l);
} }
namep[l] = '\0'; namep[l] = '\0';
/* Fixup an Apple bug where they have bogus \0 chars in the
* middle of the path in some properties
*/
for (p = namep, ep = namep + l; p < ep; p++)
if (*p == '\0') {
memmove(p, p+1, ep - p);
ep--; l--;
}
*mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4); *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4);
} }
...@@ -1599,7 +1623,10 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, ...@@ -1599,7 +1623,10 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
prev_name = RELOC(""); prev_name = RELOC("");
sstart = (char *)RELOC(dt_string_start); sstart = (char *)RELOC(dt_string_start);
for (;;) { for (;;) {
if (call_prom("nextprop", 3, 1, node, prev_name, pname) <= 0) int rc;
rc = call_prom("nextprop", 3, 1, node, prev_name, pname);
if (rc != 1)
break; break;
/* find string offset */ /* find string offset */
...@@ -1615,7 +1642,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, ...@@ -1615,7 +1642,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
l = call_prom("getproplen", 2, 1, node, pname); l = call_prom("getproplen", 2, 1, node, pname);
/* sanity checks */ /* sanity checks */
if (l < 0) if (l == PROM_ERROR)
continue; continue;
if (l > MAX_PROPERTY_LENGTH) { if (l > MAX_PROPERTY_LENGTH) {
prom_printf("WARNING: ignoring large property "); prom_printf("WARNING: ignoring large property ");
...@@ -1763,17 +1790,18 @@ static void __init fixup_device_tree(void) ...@@ -1763,17 +1790,18 @@ static void __init fixup_device_tree(void)
/* Some G5s have a missing interrupt definition, fix it up here */ /* Some G5s have a missing interrupt definition, fix it up here */
u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000")); u3 = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000"));
if ((long)u3 <= 0) if (!PHANDLE_VALID(u3))
return; return;
i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000")); i2c = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/i2c@f8001000"));
if ((long)i2c <= 0) if (!PHANDLE_VALID(i2c))
return; return;
mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000")); mpic = call_prom("finddevice", 1, 1, ADDR("/u3@0,f8000000/mpic@f8040000"));
if ((long)mpic <= 0) if (!PHANDLE_VALID(mpic))
return; return;
/* check if proper rev of u3 */ /* check if proper rev of u3 */
if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) <= 0) if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev))
== PROM_ERROR)
return; return;
if (u3_rev != 0x35) if (u3_rev != 0x35)
return; return;
......
...@@ -103,11 +103,6 @@ extern void unflatten_device_tree(void); ...@@ -103,11 +103,6 @@ extern void unflatten_device_tree(void);
extern void smp_release_cpus(void); extern void smp_release_cpus(void);
unsigned long decr_overclock = 1;
unsigned long decr_overclock_proc0 = 1;
unsigned long decr_overclock_set = 0;
unsigned long decr_overclock_proc0_set = 0;
int have_of = 1; int have_of = 1;
int boot_cpuid = 0; int boot_cpuid = 0;
int boot_cpuid_phys = 0; int boot_cpuid_phys = 0;
...@@ -1120,64 +1115,15 @@ void ppc64_dump_msg(unsigned int src, const char *msg) ...@@ -1120,64 +1115,15 @@ void ppc64_dump_msg(unsigned int src, const char *msg)
printk("[dump]%04x %s\n", src, msg); printk("[dump]%04x %s\n", src, msg);
} }
int set_spread_lpevents( char * str )
{
/* The parameter is the number of processors to share in processing lp events */
unsigned long i;
unsigned long val = simple_strtoul( str, NULL, 0 );
if ( ( val > 0 ) && ( val <= NR_CPUS ) ) {
for ( i=1; i<val; ++i )
paca[i].lpqueue_ptr = paca[0].lpqueue_ptr;
printk("lpevent processing spread over %ld processors\n", val);
}
else
printk("invalid spreaqd_lpevents %ld\n", val);
return 1;
}
/* This should only be called on processor 0 during calibrate decr */ /* This should only be called on processor 0 during calibrate decr */
void setup_default_decr(void) void setup_default_decr(void)
{ {
struct paca_struct *lpaca = get_paca(); struct paca_struct *lpaca = get_paca();
if ( decr_overclock_set && !decr_overclock_proc0_set ) lpaca->default_decr = tb_ticks_per_jiffy;
decr_overclock_proc0 = decr_overclock;
lpaca->default_decr = tb_ticks_per_jiffy / decr_overclock_proc0;
lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy; lpaca->next_jiffy_update_tb = get_tb() + tb_ticks_per_jiffy;
} }
int set_decr_overclock_proc0( char * str )
{
unsigned long val = simple_strtoul( str, NULL, 0 );
if ( ( val >= 1 ) && ( val <= 48 ) ) {
decr_overclock_proc0_set = 1;
decr_overclock_proc0 = val;
printk("proc 0 decrementer overclock factor of %ld\n", val);
}
else
printk("invalid proc 0 decrementer overclock factor of %ld\n", val);
return 1;
}
int set_decr_overclock( char * str )
{
unsigned long val = simple_strtoul( str, NULL, 0 );
if ( ( val >= 1 ) && ( val <= 48 ) ) {
decr_overclock_set = 1;
decr_overclock = val;
printk("decrementer overclock factor of %ld\n", val);
}
else
printk("invalid decrementer overclock factor of %ld\n", val);
return 1;
}
__setup("spread_lpevents=", set_spread_lpevents );
__setup("decr_overclock_proc0=", set_decr_overclock_proc0 );
__setup("decr_overclock=", set_decr_overclock );
#ifndef CONFIG_PPC_ISERIES #ifndef CONFIG_PPC_ISERIES
/* /*
* This function can be used by platforms to "find" legacy serial ports. * This function can be used by platforms to "find" legacy serial ports.
......
...@@ -334,7 +334,6 @@ void smp_call_function_interrupt(void) ...@@ -334,7 +334,6 @@ void smp_call_function_interrupt(void)
} }
} }
extern unsigned long decr_overclock;
extern struct gettimeofday_struct do_gtod; extern struct gettimeofday_struct do_gtod;
struct thread_info *current_set[NR_CPUS]; struct thread_info *current_set[NR_CPUS];
...@@ -491,7 +490,7 @@ int __devinit __cpu_up(unsigned int cpu) ...@@ -491,7 +490,7 @@ int __devinit __cpu_up(unsigned int cpu)
if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu)) if (smp_ops->cpu_bootable && !smp_ops->cpu_bootable(cpu))
return -EINVAL; return -EINVAL;
paca[cpu].default_decr = tb_ticks_per_jiffy / decr_overclock; paca[cpu].default_decr = tb_ticks_per_jiffy;
if (!cpu_has_feature(CPU_FTR_SLB)) { if (!cpu_has_feature(CPU_FTR_SLB)) {
void *tmp; void *tmp;
......
...@@ -113,7 +113,6 @@ void ppc64_enable_pmcs(void) ...@@ -113,7 +113,6 @@ void ppc64_enable_pmcs(void)
#ifdef CONFIG_PPC_PSERIES #ifdef CONFIG_PPC_PSERIES
unsigned long set, reset; unsigned long set, reset;
int ret; int ret;
unsigned int ctrl;
#endif /* CONFIG_PPC_PSERIES */ #endif /* CONFIG_PPC_PSERIES */
/* Only need to enable them once */ /* Only need to enable them once */
...@@ -167,11 +166,8 @@ void ppc64_enable_pmcs(void) ...@@ -167,11 +166,8 @@ void ppc64_enable_pmcs(void)
* On SMT machines we have to set the run latch in the ctrl register * On SMT machines we have to set the run latch in the ctrl register
* in order to make PMC6 spin. * in order to make PMC6 spin.
*/ */
if (cpu_has_feature(CPU_FTR_SMT)) { if (cpu_has_feature(CPU_FTR_SMT))
ctrl = mfspr(CTRLF); ppc64_runlatch_on();
ctrl |= RUNLATCH;
mtspr(CTRLT, ctrl);
}
#endif /* CONFIG_PPC_PSERIES */ #endif /* CONFIG_PPC_PSERIES */
} }
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
//#include <linux/kernel_stat.h> //#include <linux/kernel_stat.h>
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/workqueue.h>
#include "appldata.h" #include "appldata.h"
...@@ -133,9 +134,12 @@ static int appldata_interval = APPLDATA_CPU_INTERVAL; ...@@ -133,9 +134,12 @@ static int appldata_interval = APPLDATA_CPU_INTERVAL;
static int appldata_timer_active; static int appldata_timer_active;
/* /*
* Tasklet * Work queue
*/ */
static struct tasklet_struct appldata_tasklet_struct; static struct workqueue_struct *appldata_wq;
static void appldata_work_fn(void *data);
static DECLARE_WORK(appldata_work, appldata_work_fn, NULL);
/* /*
* Ops list * Ops list
...@@ -144,11 +148,11 @@ static DEFINE_SPINLOCK(appldata_ops_lock); ...@@ -144,11 +148,11 @@ static DEFINE_SPINLOCK(appldata_ops_lock);
static LIST_HEAD(appldata_ops_list); static LIST_HEAD(appldata_ops_list);
/************************* timer, tasklet, DIAG ******************************/ /*************************** timer, work, DIAG *******************************/
/* /*
* appldata_timer_function() * appldata_timer_function()
* *
* schedule tasklet and reschedule timer * schedule work and reschedule timer
*/ */
static void appldata_timer_function(unsigned long data, struct pt_regs *regs) static void appldata_timer_function(unsigned long data, struct pt_regs *regs)
{ {
...@@ -157,22 +161,22 @@ static void appldata_timer_function(unsigned long data, struct pt_regs *regs) ...@@ -157,22 +161,22 @@ static void appldata_timer_function(unsigned long data, struct pt_regs *regs)
atomic_read(&appldata_expire_count)); atomic_read(&appldata_expire_count));
if (atomic_dec_and_test(&appldata_expire_count)) { if (atomic_dec_and_test(&appldata_expire_count)) {
atomic_set(&appldata_expire_count, num_online_cpus()); atomic_set(&appldata_expire_count, num_online_cpus());
tasklet_schedule((struct tasklet_struct *) data); queue_work(appldata_wq, (struct work_struct *) data);
} }
} }
/* /*
* appldata_tasklet_function() * appldata_work_fn()
* *
* call data gathering function for each (active) module * call data gathering function for each (active) module
*/ */
static void appldata_tasklet_function(unsigned long data) static void appldata_work_fn(void *data)
{ {
struct list_head *lh; struct list_head *lh;
struct appldata_ops *ops; struct appldata_ops *ops;
int i; int i;
P_DEBUG(" -= Tasklet =-\n"); P_DEBUG(" -= Work Queue =-\n");
i = 0; i = 0;
spin_lock(&appldata_ops_lock); spin_lock(&appldata_ops_lock);
list_for_each(lh, &appldata_ops_list) { list_for_each(lh, &appldata_ops_list) {
...@@ -231,7 +235,7 @@ static int appldata_diag(char record_nr, u16 function, unsigned long buffer, ...@@ -231,7 +235,7 @@ static int appldata_diag(char record_nr, u16 function, unsigned long buffer,
: "=d" (ry) : "d" (&(appldata_parameter_list)) : "cc"); : "=d" (ry) : "d" (&(appldata_parameter_list)) : "cc");
return (int) ry; return (int) ry;
} }
/********************** timer, tasklet, DIAG <END> ***************************/ /************************ timer, work, DIAG <END> ****************************/
/****************************** /proc stuff **********************************/ /****************************** /proc stuff **********************************/
...@@ -411,7 +415,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, ...@@ -411,7 +415,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
struct list_head *lh; struct list_head *lh;
found = 0; found = 0;
spin_lock_bh(&appldata_ops_lock); spin_lock(&appldata_ops_lock);
list_for_each(lh, &appldata_ops_list) { list_for_each(lh, &appldata_ops_list) {
tmp_ops = list_entry(lh, struct appldata_ops, list); tmp_ops = list_entry(lh, struct appldata_ops, list);
if (&tmp_ops->ctl_table[2] == ctl) { if (&tmp_ops->ctl_table[2] == ctl) {
...@@ -419,15 +423,15 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, ...@@ -419,15 +423,15 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
} }
} }
if (!found) { if (!found) {
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
return -ENODEV; return -ENODEV;
} }
ops = ctl->data; ops = ctl->data;
if (!try_module_get(ops->owner)) { // protect this function if (!try_module_get(ops->owner)) { // protect this function
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
return -ENODEV; return -ENODEV;
} }
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
if (!*lenp || *ppos) { if (!*lenp || *ppos) {
*lenp = 0; *lenp = 0;
...@@ -451,10 +455,11 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, ...@@ -451,10 +455,11 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
return -EFAULT; return -EFAULT;
} }
spin_lock_bh(&appldata_ops_lock); spin_lock(&appldata_ops_lock);
if ((buf[0] == '1') && (ops->active == 0)) { if ((buf[0] == '1') && (ops->active == 0)) {
if (!try_module_get(ops->owner)) { // protect tasklet // protect work queue callback
spin_unlock_bh(&appldata_ops_lock); if (!try_module_get(ops->owner)) {
spin_unlock(&appldata_ops_lock);
module_put(ops->owner); module_put(ops->owner);
return -ENODEV; return -ENODEV;
} }
...@@ -485,7 +490,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, ...@@ -485,7 +490,7 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp,
} }
module_put(ops->owner); module_put(ops->owner);
} }
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
out: out:
*lenp = len; *lenp = len;
*ppos += len; *ppos += len;
...@@ -529,7 +534,7 @@ int appldata_register_ops(struct appldata_ops *ops) ...@@ -529,7 +534,7 @@ int appldata_register_ops(struct appldata_ops *ops)
} }
memset(ops->ctl_table, 0, 4*sizeof(struct ctl_table)); memset(ops->ctl_table, 0, 4*sizeof(struct ctl_table));
spin_lock_bh(&appldata_ops_lock); spin_lock(&appldata_ops_lock);
list_for_each(lh, &appldata_ops_list) { list_for_each(lh, &appldata_ops_list) {
tmp_ops = list_entry(lh, struct appldata_ops, list); tmp_ops = list_entry(lh, struct appldata_ops, list);
P_DEBUG("register_ops loop: %i) name = %s, ctl = %i\n", P_DEBUG("register_ops loop: %i) name = %s, ctl = %i\n",
...@@ -541,18 +546,18 @@ int appldata_register_ops(struct appldata_ops *ops) ...@@ -541,18 +546,18 @@ int appldata_register_ops(struct appldata_ops *ops)
APPLDATA_PROC_NAME_LENGTH) == 0) { APPLDATA_PROC_NAME_LENGTH) == 0) {
P_ERROR("Name \"%s\" already registered!\n", ops->name); P_ERROR("Name \"%s\" already registered!\n", ops->name);
kfree(ops->ctl_table); kfree(ops->ctl_table);
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
return -EBUSY; return -EBUSY;
} }
if (tmp_ops->ctl_nr == ops->ctl_nr) { if (tmp_ops->ctl_nr == ops->ctl_nr) {
P_ERROR("ctl_nr %i already registered!\n", ops->ctl_nr); P_ERROR("ctl_nr %i already registered!\n", ops->ctl_nr);
kfree(ops->ctl_table); kfree(ops->ctl_table);
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
return -EBUSY; return -EBUSY;
} }
} }
list_add(&ops->list, &appldata_ops_list); list_add(&ops->list, &appldata_ops_list);
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
ops->ctl_table[0].ctl_name = CTL_APPLDATA; ops->ctl_table[0].ctl_name = CTL_APPLDATA;
ops->ctl_table[0].procname = appldata_proc_name; ops->ctl_table[0].procname = appldata_proc_name;
...@@ -583,12 +588,12 @@ int appldata_register_ops(struct appldata_ops *ops) ...@@ -583,12 +588,12 @@ int appldata_register_ops(struct appldata_ops *ops)
*/ */
void appldata_unregister_ops(struct appldata_ops *ops) void appldata_unregister_ops(struct appldata_ops *ops)
{ {
spin_lock_bh(&appldata_ops_lock); spin_lock(&appldata_ops_lock);
unregister_sysctl_table(ops->sysctl_header); unregister_sysctl_table(ops->sysctl_header);
list_del(&ops->list); list_del(&ops->list);
kfree(ops->ctl_table); kfree(ops->ctl_table);
ops->ctl_table = NULL; ops->ctl_table = NULL;
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
P_INFO("%s-ops unregistered!\n", ops->name); P_INFO("%s-ops unregistered!\n", ops->name);
} }
/********************** module-ops management <END> **************************/ /********************** module-ops management <END> **************************/
...@@ -602,7 +607,7 @@ appldata_online_cpu(int cpu) ...@@ -602,7 +607,7 @@ appldata_online_cpu(int cpu)
init_virt_timer(&per_cpu(appldata_timer, cpu)); init_virt_timer(&per_cpu(appldata_timer, cpu));
per_cpu(appldata_timer, cpu).function = appldata_timer_function; per_cpu(appldata_timer, cpu).function = appldata_timer_function;
per_cpu(appldata_timer, cpu).data = (unsigned long) per_cpu(appldata_timer, cpu).data = (unsigned long)
&appldata_tasklet_struct; &appldata_work;
atomic_inc(&appldata_expire_count); atomic_inc(&appldata_expire_count);
spin_lock(&appldata_timer_lock); spin_lock(&appldata_timer_lock);
__appldata_vtimer_setup(APPLDATA_MOD_TIMER); __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
...@@ -615,7 +620,7 @@ appldata_offline_cpu(int cpu) ...@@ -615,7 +620,7 @@ appldata_offline_cpu(int cpu)
del_virt_timer(&per_cpu(appldata_timer, cpu)); del_virt_timer(&per_cpu(appldata_timer, cpu));
if (atomic_dec_and_test(&appldata_expire_count)) { if (atomic_dec_and_test(&appldata_expire_count)) {
atomic_set(&appldata_expire_count, num_online_cpus()); atomic_set(&appldata_expire_count, num_online_cpus());
tasklet_schedule(&appldata_tasklet_struct); queue_work(appldata_wq, &appldata_work);
} }
spin_lock(&appldata_timer_lock); spin_lock(&appldata_timer_lock);
__appldata_vtimer_setup(APPLDATA_MOD_TIMER); __appldata_vtimer_setup(APPLDATA_MOD_TIMER);
...@@ -648,7 +653,7 @@ static struct notifier_block __devinitdata appldata_nb = { ...@@ -648,7 +653,7 @@ static struct notifier_block __devinitdata appldata_nb = {
/* /*
* appldata_init() * appldata_init()
* *
* init timer and tasklet, register /proc entries * init timer, register /proc entries
*/ */
static int __init appldata_init(void) static int __init appldata_init(void)
{ {
...@@ -657,6 +662,12 @@ static int __init appldata_init(void) ...@@ -657,6 +662,12 @@ static int __init appldata_init(void)
P_DEBUG("sizeof(parameter_list) = %lu\n", P_DEBUG("sizeof(parameter_list) = %lu\n",
sizeof(struct appldata_parameter_list)); sizeof(struct appldata_parameter_list));
appldata_wq = create_singlethread_workqueue("appldata");
if (!appldata_wq) {
P_ERROR("Could not create work queue\n");
return -ENOMEM;
}
for_each_online_cpu(i) for_each_online_cpu(i)
appldata_online_cpu(i); appldata_online_cpu(i);
...@@ -670,7 +681,6 @@ static int __init appldata_init(void) ...@@ -670,7 +681,6 @@ static int __init appldata_init(void)
appldata_table[1].de->owner = THIS_MODULE; appldata_table[1].de->owner = THIS_MODULE;
#endif #endif
tasklet_init(&appldata_tasklet_struct, appldata_tasklet_function, 0);
P_DEBUG("Base interface initialized.\n"); P_DEBUG("Base interface initialized.\n");
return 0; return 0;
} }
...@@ -678,7 +688,7 @@ static int __init appldata_init(void) ...@@ -678,7 +688,7 @@ static int __init appldata_init(void)
/* /*
* appldata_exit() * appldata_exit()
* *
* stop timer and tasklet, unregister /proc entries * stop timer, unregister /proc entries
*/ */
static void __exit appldata_exit(void) static void __exit appldata_exit(void)
{ {
...@@ -690,7 +700,7 @@ static void __exit appldata_exit(void) ...@@ -690,7 +700,7 @@ static void __exit appldata_exit(void)
/* /*
* ops list should be empty, but just in case something went wrong... * ops list should be empty, but just in case something went wrong...
*/ */
spin_lock_bh(&appldata_ops_lock); spin_lock(&appldata_ops_lock);
list_for_each(lh, &appldata_ops_list) { list_for_each(lh, &appldata_ops_list) {
ops = list_entry(lh, struct appldata_ops, list); ops = list_entry(lh, struct appldata_ops, list);
rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC, rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC,
...@@ -700,7 +710,7 @@ static void __exit appldata_exit(void) ...@@ -700,7 +710,7 @@ static void __exit appldata_exit(void)
"return code: %d\n", ops->name, rc); "return code: %d\n", ops->name, rc);
} }
} }
spin_unlock_bh(&appldata_ops_lock); spin_unlock(&appldata_ops_lock);
for_each_online_cpu(i) for_each_online_cpu(i)
appldata_offline_cpu(i); appldata_offline_cpu(i);
...@@ -709,7 +719,7 @@ static void __exit appldata_exit(void) ...@@ -709,7 +719,7 @@ static void __exit appldata_exit(void)
unregister_sysctl_table(appldata_sysctl_header); unregister_sysctl_table(appldata_sysctl_header);
tasklet_kill(&appldata_tasklet_struct); destroy_workqueue(appldata_wq);
P_DEBUG("... module unloaded!\n"); P_DEBUG("... module unloaded!\n");
} }
/**************************** init / exit <END> ******************************/ /**************************** init / exit <END> ******************************/
......
...@@ -68,7 +68,7 @@ struct appldata_mem_data { ...@@ -68,7 +68,7 @@ struct appldata_mem_data {
u64 pgmajfault; /* page faults (major only) */ u64 pgmajfault; /* page faults (major only) */
// <-- New in 2.6 // <-- New in 2.6
} appldata_mem_data; } __attribute__((packed)) appldata_mem_data;
static inline void appldata_debug_print(struct appldata_mem_data *mem_data) static inline void appldata_debug_print(struct appldata_mem_data *mem_data)
......
...@@ -57,7 +57,7 @@ struct appldata_net_sum_data { ...@@ -57,7 +57,7 @@ struct appldata_net_sum_data {
u64 rx_dropped; /* no space in linux buffers */ u64 rx_dropped; /* no space in linux buffers */
u64 tx_dropped; /* no space available in linux */ u64 tx_dropped; /* no space available in linux */
u64 collisions; /* collisions while transmitting */ u64 collisions; /* collisions while transmitting */
} appldata_net_sum_data; } __attribute__((packed)) appldata_net_sum_data;
static inline void appldata_print_debug(struct appldata_net_sum_data *net_data) static inline void appldata_print_debug(struct appldata_net_sum_data *net_data)
......
...@@ -49,7 +49,7 @@ struct appldata_os_per_cpu { ...@@ -49,7 +49,7 @@ struct appldata_os_per_cpu {
u32 per_cpu_softirq; /* ... spent in softirqs */ u32 per_cpu_softirq; /* ... spent in softirqs */
u32 per_cpu_iowait; /* ... spent while waiting for I/O */ u32 per_cpu_iowait; /* ... spent while waiting for I/O */
// <-- New in 2.6 // <-- New in 2.6
}; } __attribute__((packed));
struct appldata_os_data { struct appldata_os_data {
u64 timestamp; u64 timestamp;
...@@ -75,7 +75,7 @@ struct appldata_os_data { ...@@ -75,7 +75,7 @@ struct appldata_os_data {
/* per cpu data */ /* per cpu data */
struct appldata_os_per_cpu os_cpu[0]; struct appldata_os_per_cpu os_cpu[0];
}; } __attribute__((packed));
static struct appldata_os_data *appldata_os_data; static struct appldata_os_data *appldata_os_data;
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <asm/pgalloc.h> #include <asm/pgalloc.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/unistd.h>
#ifdef CONFIG_S390_SUPPORT #ifdef CONFIG_S390_SUPPORT
#include "compat_ptrace.h" #include "compat_ptrace.h"
...@@ -130,13 +131,19 @@ static int ...@@ -130,13 +131,19 @@ static int
peek_user(struct task_struct *child, addr_t addr, addr_t data) peek_user(struct task_struct *child, addr_t addr, addr_t data)
{ {
struct user *dummy = NULL; struct user *dummy = NULL;
addr_t offset, tmp; addr_t offset, tmp, mask;
/* /*
* Stupid gdb peeks/pokes the access registers in 64 bit with * Stupid gdb peeks/pokes the access registers in 64 bit with
* an alignment of 4. Programmers from hell... * an alignment of 4. Programmers from hell...
*/ */
if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK) mask = __ADDR_MASK;
#ifdef CONFIG_ARCH_S390X
if (addr >= (addr_t) &dummy->regs.acrs &&
addr < (addr_t) &dummy->regs.orig_gpr2)
mask = 3;
#endif
if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
return -EIO; return -EIO;
if (addr < (addr_t) &dummy->regs.acrs) { if (addr < (addr_t) &dummy->regs.acrs) {
...@@ -153,6 +160,16 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data) ...@@ -153,6 +160,16 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data)
* access registers are stored in the thread structure * access registers are stored in the thread structure
*/ */
offset = addr - (addr_t) &dummy->regs.acrs; offset = addr - (addr_t) &dummy->regs.acrs;
#ifdef CONFIG_ARCH_S390X
/*
* Very special case: old & broken 64 bit gdb reading
* from acrs[15]. Result is a 64 bit value. Read the
* 32 bit acrs[15] value and shift it by 32. Sick...
*/
if (addr == (addr_t) &dummy->regs.acrs[15])
tmp = ((unsigned long) child->thread.acrs[15]) << 32;
else
#endif
tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset); tmp = *(addr_t *)((addr_t) &child->thread.acrs + offset);
} else if (addr == (addr_t) &dummy->regs.orig_gpr2) { } else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
...@@ -167,6 +184,9 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data) ...@@ -167,6 +184,9 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data)
*/ */
offset = addr - (addr_t) &dummy->regs.fp_regs; offset = addr - (addr_t) &dummy->regs.fp_regs;
tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset); tmp = *(addr_t *)((addr_t) &child->thread.fp_regs + offset);
if (addr == (addr_t) &dummy->regs.fp_regs.fpc)
tmp &= (unsigned long) FPC_VALID_MASK
<< (BITS_PER_LONG - 32);
} else if (addr < (addr_t) (&dummy->regs.per_info + 1)) { } else if (addr < (addr_t) (&dummy->regs.per_info + 1)) {
/* /*
...@@ -191,13 +211,19 @@ static int ...@@ -191,13 +211,19 @@ static int
poke_user(struct task_struct *child, addr_t addr, addr_t data) poke_user(struct task_struct *child, addr_t addr, addr_t data)
{ {
struct user *dummy = NULL; struct user *dummy = NULL;
addr_t offset; addr_t offset, mask;
/* /*
* Stupid gdb peeks/pokes the access registers in 64 bit with * Stupid gdb peeks/pokes the access registers in 64 bit with
* an alignment of 4. Programmers from hell indeed... * an alignment of 4. Programmers from hell indeed...
*/ */
if ((addr & 3) || addr > sizeof(struct user) - __ADDR_MASK) mask = __ADDR_MASK;
#ifdef CONFIG_ARCH_S390X
if (addr >= (addr_t) &dummy->regs.acrs &&
addr < (addr_t) &dummy->regs.orig_gpr2)
mask = 3;
#endif
if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK)
return -EIO; return -EIO;
if (addr < (addr_t) &dummy->regs.acrs) { if (addr < (addr_t) &dummy->regs.acrs) {
...@@ -224,6 +250,17 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data) ...@@ -224,6 +250,17 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
* access registers are stored in the thread structure * access registers are stored in the thread structure
*/ */
offset = addr - (addr_t) &dummy->regs.acrs; offset = addr - (addr_t) &dummy->regs.acrs;
#ifdef CONFIG_ARCH_S390X
/*
* Very special case: old & broken 64 bit gdb writing
* to acrs[15] with a 64 bit value. Ignore the lower
* half of the value and write the upper 32 bit to
* acrs[15]. Sick...
*/
if (addr == (addr_t) &dummy->regs.acrs[15])
child->thread.acrs[15] = (unsigned int) (data >> 32);
else
#endif
*(addr_t *)((addr_t) &child->thread.acrs + offset) = data; *(addr_t *)((addr_t) &child->thread.acrs + offset) = data;
} else if (addr == (addr_t) &dummy->regs.orig_gpr2) { } else if (addr == (addr_t) &dummy->regs.orig_gpr2) {
...@@ -237,7 +274,8 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data) ...@@ -237,7 +274,8 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
* floating point regs. are stored in the thread structure * floating point regs. are stored in the thread structure
*/ */
if (addr == (addr_t) &dummy->regs.fp_regs.fpc && if (addr == (addr_t) &dummy->regs.fp_regs.fpc &&
(data & ~FPC_VALID_MASK) != 0) (data & ~((unsigned long) FPC_VALID_MASK
<< (BITS_PER_LONG - 32))) != 0)
return -EINVAL; return -EINVAL;
offset = addr - (addr_t) &dummy->regs.fp_regs; offset = addr - (addr_t) &dummy->regs.fp_regs;
*(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data; *(addr_t *)((addr_t) &child->thread.fp_regs + offset) = data;
...@@ -722,6 +760,13 @@ syscall_trace(struct pt_regs *regs, int entryexit) ...@@ -722,6 +760,13 @@ syscall_trace(struct pt_regs *regs, int entryexit)
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0)); ? 0x80 : 0));
/*
* If the debuffer has set an invalid system call number,
* we prepare to skip the system call restart handling.
*/
if (!entryexit && regs->gprs[2] >= NR_syscalls)
regs->trap = -1;
/* /*
* this isn't the same as continuing with a signal, but it will do * this isn't the same as continuing with a signal, but it will do
* for normal use. strace only continues with a signal if the * for normal use. strace only continues with a signal if the
......
...@@ -207,7 +207,7 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection) ...@@ -207,7 +207,7 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
* we are not in an interrupt and that there is a * we are not in an interrupt and that there is a
* user context. * user context.
*/ */
if (user_address == 0 || in_interrupt() || !mm) if (user_address == 0 || in_atomic() || !mm)
goto no_context; goto no_context;
/* /*
......
...@@ -196,6 +196,34 @@ static iopte_t *alloc_consistent_cluster(struct pci_iommu *iommu, unsigned long ...@@ -196,6 +196,34 @@ static iopte_t *alloc_consistent_cluster(struct pci_iommu *iommu, unsigned long
return NULL; return NULL;
} }
static int iommu_alloc_ctx(struct pci_iommu *iommu)
{
int lowest = iommu->ctx_lowest_free;
int sz = IOMMU_NUM_CTXS - lowest;
int n = find_next_zero_bit(iommu->ctx_bitmap, sz, lowest);
if (unlikely(n == sz)) {
n = find_next_zero_bit(iommu->ctx_bitmap, lowest, 1);
if (unlikely(n == lowest)) {
printk(KERN_WARNING "IOMMU: Ran out of contexts.\n");
n = 0;
}
}
if (n)
__set_bit(n, iommu->ctx_bitmap);
return n;
}
static inline void iommu_free_ctx(struct pci_iommu *iommu, int ctx)
{
if (likely(ctx)) {
__clear_bit(ctx, iommu->ctx_bitmap);
if (ctx < iommu->ctx_lowest_free)
iommu->ctx_lowest_free = ctx;
}
}
/* Allocate and map kernel buffer of size SIZE using consistent mode /* Allocate and map kernel buffer of size SIZE using consistent mode
* DMA for PCI device PDEV. Return non-NULL cpu-side address if * DMA for PCI device PDEV. Return non-NULL cpu-side address if
* successful and set *DMA_ADDRP to the PCI side dma address. * successful and set *DMA_ADDRP to the PCI side dma address.
...@@ -236,7 +264,7 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad ...@@ -236,7 +264,7 @@ void *pci_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_ad
npages = size >> IO_PAGE_SHIFT; npages = size >> IO_PAGE_SHIFT;
ctx = 0; ctx = 0;
if (iommu->iommu_ctxflush) if (iommu->iommu_ctxflush)
ctx = iommu->iommu_cur_ctx++; ctx = iommu_alloc_ctx(iommu);
first_page = __pa(first_page); first_page = __pa(first_page);
while (npages--) { while (npages--) {
iopte_val(*iopte) = (IOPTE_CONSISTENT(ctx) | iopte_val(*iopte) = (IOPTE_CONSISTENT(ctx) |
...@@ -317,6 +345,8 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_ ...@@ -317,6 +345,8 @@ void pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_
} }
} }
iommu_free_ctx(iommu, ctx);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
order = get_order(size); order = get_order(size);
...@@ -360,7 +390,7 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direct ...@@ -360,7 +390,7 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direct
base_paddr = __pa(oaddr & IO_PAGE_MASK); base_paddr = __pa(oaddr & IO_PAGE_MASK);
ctx = 0; ctx = 0;
if (iommu->iommu_ctxflush) if (iommu->iommu_ctxflush)
ctx = iommu->iommu_cur_ctx++; ctx = iommu_alloc_ctx(iommu);
if (strbuf->strbuf_enabled) if (strbuf->strbuf_enabled)
iopte_protection = IOPTE_STREAMING(ctx); iopte_protection = IOPTE_STREAMING(ctx);
else else
...@@ -380,39 +410,53 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direct ...@@ -380,39 +410,53 @@ dma_addr_t pci_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direct
return PCI_DMA_ERROR_CODE; return PCI_DMA_ERROR_CODE;
} }
static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages) static void pci_strbuf_flush(struct pci_strbuf *strbuf, struct pci_iommu *iommu, u32 vaddr, unsigned long ctx, unsigned long npages, int direction)
{ {
int limit; int limit;
PCI_STC_FLUSHFLAG_INIT(strbuf);
if (strbuf->strbuf_ctxflush && if (strbuf->strbuf_ctxflush &&
iommu->iommu_ctxflush) { iommu->iommu_ctxflush) {
unsigned long matchreg, flushreg; unsigned long matchreg, flushreg;
u64 val;
flushreg = strbuf->strbuf_ctxflush; flushreg = strbuf->strbuf_ctxflush;
matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx); matchreg = PCI_STC_CTXMATCH_ADDR(strbuf, ctx);
limit = 100000;
pci_iommu_write(flushreg, ctx); pci_iommu_write(flushreg, ctx);
for(;;) { val = pci_iommu_read(matchreg);
if (((long)pci_iommu_read(matchreg)) >= 0L) val &= 0xffff;
break; if (!val)
limit--; goto do_flush_sync;
if (!limit)
break; while (val) {
udelay(1); if (val & 0x1)
pci_iommu_write(flushreg, ctx);
val >>= 1;
} }
if (!limit) val = pci_iommu_read(matchreg);
if (unlikely(val)) {
printk(KERN_WARNING "pci_strbuf_flush: ctx flush " printk(KERN_WARNING "pci_strbuf_flush: ctx flush "
"timeout vaddr[%08x] ctx[%lx]\n", "timeout matchreg[%lx] ctx[%lx]\n",
vaddr, ctx); val, ctx);
goto do_page_flush;
}
} else { } else {
unsigned long i; unsigned long i;
do_page_flush:
for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE) for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE)
pci_iommu_write(strbuf->strbuf_pflush, vaddr); pci_iommu_write(strbuf->strbuf_pflush, vaddr);
} }
do_flush_sync:
/* If the device could not have possibly put dirty data into
* the streaming cache, no flush-flag synchronization needs
* to be performed.
*/
if (direction == PCI_DMA_TODEVICE)
return;
PCI_STC_FLUSHFLAG_INIT(strbuf);
pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
(void) pci_iommu_read(iommu->write_complete_reg); (void) pci_iommu_read(iommu->write_complete_reg);
...@@ -466,7 +510,7 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int ...@@ -466,7 +510,7 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int
/* Step 1: Kick data out of streaming buffers if necessary. */ /* Step 1: Kick data out of streaming buffers if necessary. */
if (strbuf->strbuf_enabled) if (strbuf->strbuf_enabled)
pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
/* Step 2: Clear out first TSB entry. */ /* Step 2: Clear out first TSB entry. */
iopte_make_dummy(iommu, base); iopte_make_dummy(iommu, base);
...@@ -474,6 +518,8 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int ...@@ -474,6 +518,8 @@ void pci_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int
free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base,
npages, ctx); npages, ctx);
iommu_free_ctx(iommu, ctx);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
...@@ -613,7 +659,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int ...@@ -613,7 +659,7 @@ int pci_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int
/* Step 4: Choose a context if necessary. */ /* Step 4: Choose a context if necessary. */
ctx = 0; ctx = 0;
if (iommu->iommu_ctxflush) if (iommu->iommu_ctxflush)
ctx = iommu->iommu_cur_ctx++; ctx = iommu_alloc_ctx(iommu);
/* Step 5: Create the mappings. */ /* Step 5: Create the mappings. */
if (strbuf->strbuf_enabled) if (strbuf->strbuf_enabled)
...@@ -678,7 +724,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, ...@@ -678,7 +724,7 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
/* Step 1: Kick data out of streaming buffers if necessary. */ /* Step 1: Kick data out of streaming buffers if necessary. */
if (strbuf->strbuf_enabled) if (strbuf->strbuf_enabled)
pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
/* Step 2: Clear out first TSB entry. */ /* Step 2: Clear out first TSB entry. */
iopte_make_dummy(iommu, base); iopte_make_dummy(iommu, base);
...@@ -686,6 +732,8 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, ...@@ -686,6 +732,8 @@ void pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems,
free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base, free_streaming_cluster(iommu, bus_addr - iommu->page_table_map_base,
npages, ctx); npages, ctx);
iommu_free_ctx(iommu, ctx);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
...@@ -724,7 +772,7 @@ void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size ...@@ -724,7 +772,7 @@ void pci_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size
} }
/* Step 2: Kick data out of streaming buffers. */ /* Step 2: Kick data out of streaming buffers. */
pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
...@@ -768,7 +816,7 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, i ...@@ -768,7 +816,7 @@ void pci_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, i
i--; i--;
npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length)
- bus_addr) >> IO_PAGE_SHIFT; - bus_addr) >> IO_PAGE_SHIFT;
pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages); pci_strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
......
...@@ -1212,7 +1212,7 @@ static void __init psycho_iommu_init(struct pci_controller_info *p) ...@@ -1212,7 +1212,7 @@ static void __init psycho_iommu_init(struct pci_controller_info *p)
/* Setup initial software IOMMU state. */ /* Setup initial software IOMMU state. */
spin_lock_init(&iommu->lock); spin_lock_init(&iommu->lock);
iommu->iommu_cur_ctx = 0; iommu->ctx_lowest_free = 1;
/* Register addresses. */ /* Register addresses. */
iommu->iommu_control = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL; iommu->iommu_control = p->pbm_A.controller_regs + PSYCHO_IOMMU_CONTROL;
......
...@@ -1265,7 +1265,7 @@ static void __init sabre_iommu_init(struct pci_controller_info *p, ...@@ -1265,7 +1265,7 @@ static void __init sabre_iommu_init(struct pci_controller_info *p,
/* Setup initial software IOMMU state. */ /* Setup initial software IOMMU state. */
spin_lock_init(&iommu->lock); spin_lock_init(&iommu->lock);
iommu->iommu_cur_ctx = 0; iommu->ctx_lowest_free = 1;
/* Register addresses. */ /* Register addresses. */
iommu->iommu_control = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL; iommu->iommu_control = p->pbm_A.controller_regs + SABRE_IOMMU_CONTROL;
......
...@@ -1753,7 +1753,7 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm) ...@@ -1753,7 +1753,7 @@ static void schizo_pbm_iommu_init(struct pci_pbm_info *pbm)
/* Setup initial software IOMMU state. */ /* Setup initial software IOMMU state. */
spin_lock_init(&iommu->lock); spin_lock_init(&iommu->lock);
iommu->iommu_cur_ctx = 0; iommu->ctx_lowest_free = 1;
/* Register addresses, SCHIZO has iommu ctx flushing. */ /* Register addresses, SCHIZO has iommu ctx flushing. */
iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL; iommu->iommu_control = pbm->pbm_regs + SCHIZO_IOMMU_CONTROL;
......
...@@ -117,17 +117,25 @@ static void iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages ...@@ -117,17 +117,25 @@ static void iommu_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages
#define STRBUF_TAG_VALID 0x02UL #define STRBUF_TAG_VALID 0x02UL
static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages) static void sbus_strbuf_flush(struct sbus_iommu *iommu, u32 base, unsigned long npages, int direction)
{ {
unsigned long n; unsigned long n;
int limit; int limit;
iommu->strbuf_flushflag = 0UL;
n = npages; n = npages;
while (n--) while (n--)
upa_writeq(base + (n << IO_PAGE_SHIFT), upa_writeq(base + (n << IO_PAGE_SHIFT),
iommu->strbuf_regs + STRBUF_PFLUSH); iommu->strbuf_regs + STRBUF_PFLUSH);
/* If the device could not have possibly put dirty data into
* the streaming cache, no flush-flag synchronization needs
* to be performed.
*/
if (direction == SBUS_DMA_TODEVICE)
return;
iommu->strbuf_flushflag = 0UL;
/* Whoopee cushion! */ /* Whoopee cushion! */
upa_writeq(__pa(&iommu->strbuf_flushflag), upa_writeq(__pa(&iommu->strbuf_flushflag),
iommu->strbuf_regs + STRBUF_FSYNC); iommu->strbuf_regs + STRBUF_FSYNC);
...@@ -421,7 +429,7 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size, ...@@ -421,7 +429,7 @@ void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t dma_addr, size_t size,
spin_lock_irqsave(&iommu->lock, flags); spin_lock_irqsave(&iommu->lock, flags);
free_streaming_cluster(iommu, dma_base, size >> IO_PAGE_SHIFT); free_streaming_cluster(iommu, dma_base, size >> IO_PAGE_SHIFT);
sbus_strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT); sbus_strbuf_flush(iommu, dma_base, size >> IO_PAGE_SHIFT, direction);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
...@@ -584,7 +592,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int ...@@ -584,7 +592,7 @@ void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int nents, int
iommu = sdev->bus->iommu; iommu = sdev->bus->iommu;
spin_lock_irqsave(&iommu->lock, flags); spin_lock_irqsave(&iommu->lock, flags);
free_streaming_cluster(iommu, dvma_base, size >> IO_PAGE_SHIFT); free_streaming_cluster(iommu, dvma_base, size >> IO_PAGE_SHIFT);
sbus_strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT); sbus_strbuf_flush(iommu, dvma_base, size >> IO_PAGE_SHIFT, direction);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
...@@ -596,7 +604,7 @@ void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t base, size_t ...@@ -596,7 +604,7 @@ void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t base, size_t
size = (IO_PAGE_ALIGN(base + size) - (base & IO_PAGE_MASK)); size = (IO_PAGE_ALIGN(base + size) - (base & IO_PAGE_MASK));
spin_lock_irqsave(&iommu->lock, flags); spin_lock_irqsave(&iommu->lock, flags);
sbus_strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT); sbus_strbuf_flush(iommu, base & IO_PAGE_MASK, size >> IO_PAGE_SHIFT, direction);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
...@@ -620,7 +628,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int ...@@ -620,7 +628,7 @@ void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int
size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base; size = IO_PAGE_ALIGN(sg[i].dma_address + sg[i].dma_length) - base;
spin_lock_irqsave(&iommu->lock, flags); spin_lock_irqsave(&iommu->lock, flags);
sbus_strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT); sbus_strbuf_flush(iommu, base, size >> IO_PAGE_SHIFT, direction);
spin_unlock_irqrestore(&iommu->lock, flags); spin_unlock_irqrestore(&iommu->lock, flags);
} }
......
...@@ -39,7 +39,8 @@ ifeq ($(CONFIG_ATM_FORE200E_PCA),y) ...@@ -39,7 +39,8 @@ ifeq ($(CONFIG_ATM_FORE200E_PCA),y)
fore_200e-objs += fore200e_pca_fw.o fore_200e-objs += fore200e_pca_fw.o
# guess the target endianess to choose the right PCA-200E firmware image # guess the target endianess to choose the right PCA-200E firmware image
ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y) ifeq ($(CONFIG_ATM_FORE200E_PCA_DEFAULT_FW),y)
CONFIG_ATM_FORE200E_PCA_FW = $(shell if test -n "`$(CC) -E -dM $(src)/../../include/asm/byteorder.h | grep ' __LITTLE_ENDIAN '`"; then echo $(obj)/pca200e.bin; else echo $(obj)/pca200e_ecd.bin2; fi) byteorder.h := include$(if $(patsubst $(srctree),,$(objtree)),2)/asm/byteorder.h
CONFIG_ATM_FORE200E_PCA_FW := $(obj)/pca200e$(if $(shell $(CC) -E -dM $(byteorder.h) | grep ' __LITTLE_ENDIAN '),.bin,_ecd.bin2)
endif endif
endif endif
......
...@@ -383,8 +383,7 @@ fore200e_shutdown(struct fore200e* fore200e) ...@@ -383,8 +383,7 @@ fore200e_shutdown(struct fore200e* fore200e)
switch(fore200e->state) { switch(fore200e->state) {
case FORE200E_STATE_COMPLETE: case FORE200E_STATE_COMPLETE:
if (fore200e->stats) kfree(fore200e->stats);
kfree(fore200e->stats);
case FORE200E_STATE_IRQ: case FORE200E_STATE_IRQ:
free_irq(fore200e->irq, fore200e->atm_dev); free_irq(fore200e->irq, fore200e->atm_dev);
...@@ -963,8 +962,7 @@ fore200e_tx_irq(struct fore200e* fore200e) ...@@ -963,8 +962,7 @@ fore200e_tx_irq(struct fore200e* fore200e)
entry, txq->tail, entry->vc_map, entry->skb); entry, txq->tail, entry->vc_map, entry->skb);
/* free copy of misaligned data */ /* free copy of misaligned data */
if (entry->data) kfree(entry->data);
kfree(entry->data);
/* remove DMA mapping */ /* remove DMA mapping */
fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length, fore200e->bus->dma_unmap(fore200e, entry->tpd->tsd[ 0 ].buffer, entry->tpd->tsd[ 0 ].length,
......
...@@ -412,8 +412,7 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent) ...@@ -412,8 +412,7 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
init_one_failure: init_one_failure:
if (atm_dev) if (atm_dev)
atm_dev_deregister(atm_dev); atm_dev_deregister(atm_dev);
if (he_dev) kfree(he_dev);
kfree(he_dev);
pci_disable_device(pci_dev); pci_disable_device(pci_dev);
return err; return err;
} }
...@@ -2534,8 +2533,7 @@ he_open(struct atm_vcc *vcc) ...@@ -2534,8 +2533,7 @@ he_open(struct atm_vcc *vcc)
open_failed: open_failed:
if (err) { if (err) {
if (he_vcc) kfree(he_vcc);
kfree(he_vcc);
clear_bit(ATM_VF_ADDR, &vcc->flags); clear_bit(ATM_VF_ADDR, &vcc->flags);
} }
else else
......
...@@ -676,10 +676,10 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev) ...@@ -676,10 +676,10 @@ static int __devinit ns_init_card(int i, struct pci_dev *pcidev)
PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base); PRINTK("nicstar%d: RSQ base at 0x%x.\n", i, (u32) card->rsq.base);
/* Initialize SCQ0, the only VBR SCQ used */ /* Initialize SCQ0, the only VBR SCQ used */
card->scq1 = (scq_info *) NULL; card->scq1 = NULL;
card->scq2 = (scq_info *) NULL; card->scq2 = NULL;
card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0); card->scq0 = get_scq(VBR_SCQSIZE, NS_VRSCD0);
if (card->scq0 == (scq_info *) NULL) if (card->scq0 == NULL)
{ {
printk("nicstar%d: can't get SCQ0.\n", i); printk("nicstar%d: can't get SCQ0.\n", i);
error = 12; error = 12;
...@@ -993,24 +993,24 @@ static scq_info *get_scq(int size, u32 scd) ...@@ -993,24 +993,24 @@ static scq_info *get_scq(int size, u32 scd)
int i; int i;
if (size != VBR_SCQSIZE && size != CBR_SCQSIZE) if (size != VBR_SCQSIZE && size != CBR_SCQSIZE)
return (scq_info *) NULL; return NULL;
scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL); scq = (scq_info *) kmalloc(sizeof(scq_info), GFP_KERNEL);
if (scq == (scq_info *) NULL) if (scq == NULL)
return (scq_info *) NULL; return NULL;
scq->org = kmalloc(2 * size, GFP_KERNEL); scq->org = kmalloc(2 * size, GFP_KERNEL);
if (scq->org == NULL) if (scq->org == NULL)
{ {
kfree(scq); kfree(scq);
return (scq_info *) NULL; return NULL;
} }
scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) * scq->skb = (struct sk_buff **) kmalloc(sizeof(struct sk_buff *) *
(size / NS_SCQE_SIZE), GFP_KERNEL); (size / NS_SCQE_SIZE), GFP_KERNEL);
if (scq->skb == (struct sk_buff **) NULL) if (scq->skb == NULL)
{ {
kfree(scq->org); kfree(scq->org);
kfree(scq); kfree(scq);
return (scq_info *) NULL; return NULL;
} }
scq->num_entries = size / NS_SCQE_SIZE; scq->num_entries = size / NS_SCQE_SIZE;
scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size); scq->base = (ns_scqe *) ALIGN_ADDRESS(scq->org, size);
...@@ -1498,7 +1498,7 @@ static int ns_open(struct atm_vcc *vcc) ...@@ -1498,7 +1498,7 @@ static int ns_open(struct atm_vcc *vcc)
vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE; vc->cbr_scd = NS_FRSCD + frscdi * NS_FRSCD_SIZE;
scq = get_scq(CBR_SCQSIZE, vc->cbr_scd); scq = get_scq(CBR_SCQSIZE, vc->cbr_scd);
if (scq == (scq_info *) NULL) if (scq == NULL)
{ {
PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index); PRINTK("nicstar%d: can't get fixed rate SCQ.\n", card->index);
card->scd2vc[frscdi] = NULL; card->scd2vc[frscdi] = NULL;
......
...@@ -902,7 +902,7 @@ static void close_tx(struct atm_vcc *vcc) ...@@ -902,7 +902,7 @@ static void close_tx(struct atm_vcc *vcc)
zatm_dev->tx_bw += vcc->qos.txtp.min_pcr; zatm_dev->tx_bw += vcc->qos.txtp.min_pcr;
dealloc_shaper(vcc->dev,zatm_vcc->shaper); dealloc_shaper(vcc->dev,zatm_vcc->shaper);
} }
if (zatm_vcc->ring) kfree(zatm_vcc->ring); kfree(zatm_vcc->ring);
} }
...@@ -1339,12 +1339,9 @@ static int __init zatm_start(struct atm_dev *dev) ...@@ -1339,12 +1339,9 @@ static int __init zatm_start(struct atm_dev *dev)
return 0; return 0;
out: out:
for (i = 0; i < NR_MBX; i++) for (i = 0; i < NR_MBX; i++)
if (zatm_dev->mbx_start[i] != 0) kfree(zatm_dev->mbx_start[i]);
kfree((void *) zatm_dev->mbx_start[i]); kfree(zatm_dev->rx_map);
if (zatm_dev->rx_map != NULL) kfree(zatm_dev->tx_map);
kfree(zatm_dev->rx_map);
if (zatm_dev->tx_map != NULL)
kfree(zatm_dev->tx_map);
free_irq(zatm_dev->irq, dev); free_irq(zatm_dev->irq, dev);
return error; return error;
} }
......
此差异已折叠。
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
* i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge * i2c-ali1563.c - i2c driver for the ALi 1563 Southbridge
* *
* Copyright (C) 2004 Patrick Mochel * Copyright (C) 2004 Patrick Mochel
* 2005 Rudolf Marek <r.marek@sh.cvut.cz>
* *
* The 1563 southbridge is deceptively similar to the 1533, with a * The 1563 southbridge is deceptively similar to the 1533, with a
* few notable exceptions. One of those happens to be the fact they * few notable exceptions. One of those happens to be the fact they
...@@ -57,10 +58,11 @@ ...@@ -57,10 +58,11 @@
#define HST_CNTL2_BLOCK 0x05 #define HST_CNTL2_BLOCK 0x05
#define HST_CNTL2_SIZEMASK 0x38
static unsigned short ali1563_smba; static unsigned short ali1563_smba;
static int ali1563_transaction(struct i2c_adapter * a) static int ali1563_transaction(struct i2c_adapter * a, int size)
{ {
u32 data; u32 data;
int timeout; int timeout;
...@@ -73,7 +75,7 @@ static int ali1563_transaction(struct i2c_adapter * a) ...@@ -73,7 +75,7 @@ static int ali1563_transaction(struct i2c_adapter * a)
data = inb_p(SMB_HST_STS); data = inb_p(SMB_HST_STS);
if (data & HST_STS_BAD) { if (data & HST_STS_BAD) {
dev_warn(&a->dev,"ali1563: Trying to reset busy device\n"); dev_err(&a->dev, "ali1563: Trying to reset busy device\n");
outb_p(data | HST_STS_BAD,SMB_HST_STS); outb_p(data | HST_STS_BAD,SMB_HST_STS);
data = inb_p(SMB_HST_STS); data = inb_p(SMB_HST_STS);
if (data & HST_STS_BAD) if (data & HST_STS_BAD)
...@@ -94,19 +96,31 @@ static int ali1563_transaction(struct i2c_adapter * a) ...@@ -94,19 +96,31 @@ static int ali1563_transaction(struct i2c_adapter * a)
if (timeout && !(data & HST_STS_BAD)) if (timeout && !(data & HST_STS_BAD))
return 0; return 0;
dev_warn(&a->dev, "SMBus Error: %s%s%s%s%s\n",
timeout ? "Timeout " : "",
data & HST_STS_FAIL ? "Transaction Failed " : "",
data & HST_STS_BUSERR ? "No response or Bus Collision " : "",
data & HST_STS_DEVERR ? "Device Error " : "",
!(data & HST_STS_DONE) ? "Transaction Never Finished " : "");
if (!(data & HST_STS_DONE)) if (!timeout) {
dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n");
/* Issue 'kill' to host controller */ /* Issue 'kill' to host controller */
outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2); outb_p(HST_CNTL2_KILL,SMB_HST_CNTL2);
else data = inb_p(SMB_HST_STS);
/* Issue timeout to reset all devices on bus */ }
/* device error - no response, ignore the autodetection case */
if ((data & HST_STS_DEVERR) && (size != HST_CNTL2_QUICK)) {
dev_err(&a->dev, "Device error!\n");
}
/* bus collision */
if (data & HST_STS_BUSERR) {
dev_err(&a->dev, "Bus collision!\n");
/* Issue timeout, hoping it helps */
outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1); outb_p(HST_CNTL1_TIMEOUT,SMB_HST_CNTL1);
}
if (data & HST_STS_FAIL) {
dev_err(&a->dev, "Cleaning fail after KILL!\n");
outb_p(0x0,SMB_HST_CNTL2);
}
return -1; return -1;
} }
...@@ -149,7 +163,7 @@ static int ali1563_block_start(struct i2c_adapter * a) ...@@ -149,7 +163,7 @@ static int ali1563_block_start(struct i2c_adapter * a)
if (timeout && !(data & HST_STS_BAD)) if (timeout && !(data & HST_STS_BAD))
return 0; return 0;
dev_warn(&a->dev, "SMBus Error: %s%s%s%s%s\n", dev_err(&a->dev, "SMBus Error: %s%s%s%s%s\n",
timeout ? "Timeout " : "", timeout ? "Timeout " : "",
data & HST_STS_FAIL ? "Transaction Failed " : "", data & HST_STS_FAIL ? "Transaction Failed " : "",
data & HST_STS_BUSERR ? "No response or Bus Collision " : "", data & HST_STS_BUSERR ? "No response or Bus Collision " : "",
...@@ -242,13 +256,15 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr, ...@@ -242,13 +256,15 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr,
} }
outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD); outb_p(((addr & 0x7f) << 1) | (rw & 0x01), SMB_HST_ADD);
outb_p(inb_p(SMB_HST_CNTL2) | (size << 3), SMB_HST_CNTL2); outb_p((inb_p(SMB_HST_CNTL2) & ~HST_CNTL2_SIZEMASK) | (size << 3), SMB_HST_CNTL2);
/* Write the command register */ /* Write the command register */
switch(size) { switch(size) {
case HST_CNTL2_BYTE: case HST_CNTL2_BYTE:
if (rw== I2C_SMBUS_WRITE) if (rw== I2C_SMBUS_WRITE)
outb_p(cmd, SMB_HST_CMD); /* Beware it uses DAT0 register and not CMD! */
outb_p(cmd, SMB_HST_DAT0);
break; break;
case HST_CNTL2_BYTE_DATA: case HST_CNTL2_BYTE_DATA:
outb_p(cmd, SMB_HST_CMD); outb_p(cmd, SMB_HST_CMD);
...@@ -268,7 +284,7 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr, ...@@ -268,7 +284,7 @@ static s32 ali1563_access(struct i2c_adapter * a, u16 addr,
goto Done; goto Done;
} }
if ((error = ali1563_transaction(a))) if ((error = ali1563_transaction(a, size)))
goto Done; goto Done;
if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK)) if ((rw == I2C_SMBUS_WRITE) || (size == HST_CNTL2_QUICK))
......
...@@ -72,6 +72,7 @@ static struct amd_ide_chip { ...@@ -72,6 +72,7 @@ static struct amd_ide_chip {
{ PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 }, { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 },
{ 0 } { 0 }
}; };
...@@ -487,6 +488,7 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = { ...@@ -487,6 +488,7 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
/* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"), /* 12 */ DECLARE_NV_DEV("NFORCE3-250-SATA2"),
/* 13 */ DECLARE_NV_DEV("NFORCE-CK804"), /* 13 */ DECLARE_NV_DEV("NFORCE-CK804"),
/* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"), /* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"),
/* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"),
}; };
static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id) static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
...@@ -521,6 +523,7 @@ static struct pci_device_id amd74xx_pci_tbl[] = { ...@@ -521,6 +523,7 @@ static struct pci_device_id amd74xx_pci_tbl[] = {
#endif #endif
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
{ 0, }, { 0, },
}; };
MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl); MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
......
...@@ -374,29 +374,6 @@ static inline void do_kiss_params(struct baycom_state *bc, ...@@ -374,29 +374,6 @@ static inline void do_kiss_params(struct baycom_state *bc,
} }
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
/*
* high performance HDLC encoder
* yes, it's ugly, but generates pretty good code
*/
#define ENCODEITERA(j) \
({ \
if (!(notbitstream & (0x1f0 << j))) \
goto stuff##j; \
encodeend##j: ; \
})
#define ENCODEITERB(j) \
({ \
stuff##j: \
bitstream &= ~(0x100 << j); \
bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) | \
((bitbuf & ~(((2 << j) << numbit) - 1)) << 1); \
numbit++; \
notbitstream = ~bitstream; \
goto encodeend##j; \
})
static void encode_hdlc(struct baycom_state *bc) static void encode_hdlc(struct baycom_state *bc)
{ {
...@@ -405,6 +382,7 @@ static void encode_hdlc(struct baycom_state *bc) ...@@ -405,6 +382,7 @@ static void encode_hdlc(struct baycom_state *bc)
int pkt_len; int pkt_len;
unsigned bitstream, notbitstream, bitbuf, numbit, crc; unsigned bitstream, notbitstream, bitbuf, numbit, crc;
unsigned char crcarr[2]; unsigned char crcarr[2];
int j;
if (bc->hdlctx.bufcnt > 0) if (bc->hdlctx.bufcnt > 0)
return; return;
...@@ -429,24 +407,14 @@ static void encode_hdlc(struct baycom_state *bc) ...@@ -429,24 +407,14 @@ static void encode_hdlc(struct baycom_state *bc)
pkt_len--; pkt_len--;
if (!pkt_len) if (!pkt_len)
bp = crcarr; bp = crcarr;
ENCODEITERA(0); for (j = 0; j < 8; j++)
ENCODEITERA(1); if (unlikely(!(notbitstream & (0x1f0 << j)))) {
ENCODEITERA(2); bitstream &= ~(0x100 << j);
ENCODEITERA(3); bitbuf = (bitbuf & (((2 << j) << numbit) - 1)) |
ENCODEITERA(4); ((bitbuf & ~(((2 << j) << numbit) - 1)) << 1);
ENCODEITERA(5); numbit++;
ENCODEITERA(6); notbitstream = ~bitstream;
ENCODEITERA(7); }
goto enditer;
ENCODEITERB(0);
ENCODEITERB(1);
ENCODEITERB(2);
ENCODEITERB(3);
ENCODEITERB(4);
ENCODEITERB(5);
ENCODEITERB(6);
ENCODEITERB(7);
enditer:
numbit += 8; numbit += 8;
while (numbit >= 8) { while (numbit >= 8) {
*wp++ = bitbuf; *wp++ = bitbuf;
...@@ -610,37 +578,6 @@ static void do_rxpacket(struct net_device *dev) ...@@ -610,37 +578,6 @@ static void do_rxpacket(struct net_device *dev)
bc->stats.rx_packets++; bc->stats.rx_packets++;
} }
#define DECODEITERA(j) \
({ \
if (!(notbitstream & (0x0fc << j))) /* flag or abort */ \
goto flgabrt##j; \
if ((bitstream & (0x1f8 << j)) == (0xf8 << j)) /* stuffed bit */ \
goto stuff##j; \
enditer##j: ; \
})
#define DECODEITERB(j) \
({ \
flgabrt##j: \
if (!(notbitstream & (0x1fc << j))) { /* abort received */ \
state = 0; \
goto enditer##j; \
} \
if ((bitstream & (0x1fe << j)) != (0x0fc << j)) /* flag received */ \
goto enditer##j; \
if (state) \
do_rxpacket(dev); \
bc->hdlcrx.bufcnt = 0; \
bc->hdlcrx.bufptr = bc->hdlcrx.buf; \
state = 1; \
numbits = 7-j; \
goto enditer##j; \
stuff##j: \
numbits--; \
bitbuf = (bitbuf & ((~0xff) << j)) | ((bitbuf & ~((~0xff) << j)) << 1); \
goto enditer##j; \
})
static int receive(struct net_device *dev, int cnt) static int receive(struct net_device *dev, int cnt)
{ {
struct baycom_state *bc = netdev_priv(dev); struct baycom_state *bc = netdev_priv(dev);
...@@ -649,6 +586,7 @@ static int receive(struct net_device *dev, int cnt) ...@@ -649,6 +586,7 @@ static int receive(struct net_device *dev, int cnt)
unsigned char tmp[128]; unsigned char tmp[128];
unsigned char *cp; unsigned char *cp;
int cnt2, ret = 0; int cnt2, ret = 0;
int j;
numbits = bc->hdlcrx.numbits; numbits = bc->hdlcrx.numbits;
state = bc->hdlcrx.state; state = bc->hdlcrx.state;
...@@ -669,24 +607,32 @@ static int receive(struct net_device *dev, int cnt) ...@@ -669,24 +607,32 @@ static int receive(struct net_device *dev, int cnt)
bitbuf |= (*cp) << 8; bitbuf |= (*cp) << 8;
numbits += 8; numbits += 8;
notbitstream = ~bitstream; notbitstream = ~bitstream;
DECODEITERA(0); for (j = 0; j < 8; j++) {
DECODEITERA(1);
DECODEITERA(2); /* flag or abort */
DECODEITERA(3); if (unlikely(!(notbitstream & (0x0fc << j)))) {
DECODEITERA(4);
DECODEITERA(5); /* abort received */
DECODEITERA(6); if (!(notbitstream & (0x1fc << j)))
DECODEITERA(7); state = 0;
goto enddec;
DECODEITERB(0); /* not flag received */
DECODEITERB(1); else if (!(bitstream & (0x1fe << j)) != (0x0fc << j)) {
DECODEITERB(2); if (state)
DECODEITERB(3); do_rxpacket(dev);
DECODEITERB(4); bc->hdlcrx.bufcnt = 0;
DECODEITERB(5); bc->hdlcrx.bufptr = bc->hdlcrx.buf;
DECODEITERB(6); state = 1;
DECODEITERB(7); numbits = 7-j;
enddec: }
}
/* stuffed bit */
else if (unlikely((bitstream & (0x1f8 << j)) == (0xf8 << j))) {
numbits--;
bitbuf = (bitbuf & ((~0xff) << j)) | ((bitbuf & ~((~0xff) << j)) << 1);
}
}
while (state && numbits >= 8) { while (state && numbits >= 8) {
if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) { if (bc->hdlcrx.bufcnt >= TXBUFFER_SIZE) {
state = 0; state = 0;
......
...@@ -1274,6 +1274,9 @@ static int el3_close(struct net_device *dev) ...@@ -1274,6 +1274,9 @@ static int el3_close(struct net_device *dev)
spin_lock_irqsave(&lp->window_lock, flags); spin_lock_irqsave(&lp->window_lock, flags);
update_stats(dev); update_stats(dev);
spin_unlock_irqrestore(&lp->window_lock, flags); spin_unlock_irqrestore(&lp->window_lock, flags);
/* force interrupts off */
outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
} }
link->open--; link->open--;
......
...@@ -1585,8 +1585,8 @@ rtl8169_hw_start(struct net_device *dev) ...@@ -1585,8 +1585,8 @@ rtl8169_hw_start(struct net_device *dev)
RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb); RTL_W8(ChipCmd, CmdTxEnb | CmdRxEnb);
RTL_W8(EarlyTxThres, EarlyTxThld); RTL_W8(EarlyTxThres, EarlyTxThld);
/* For gigabit rtl8169, MTU + header + CRC + VLAN */ /* Low hurts. Let's disable the filtering. */
RTL_W16(RxMaxSize, tp->rx_buf_sz); RTL_W16(RxMaxSize, 16383);
/* Set Rx Config register */ /* Set Rx Config register */
i = rtl8169_rx_config | i = rtl8169_rx_config |
...@@ -2127,6 +2127,11 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp, ...@@ -2127,6 +2127,11 @@ rtl8169_tx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
} }
} }
static inline int rtl8169_fragmented_frame(u32 status)
{
return (status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag);
}
static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc) static inline void rtl8169_rx_csum(struct sk_buff *skb, struct RxDesc *desc)
{ {
u32 opts1 = le32_to_cpu(desc->opts1); u32 opts1 = le32_to_cpu(desc->opts1);
...@@ -2177,27 +2182,41 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, ...@@ -2177,27 +2182,41 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
while (rx_left > 0) { while (rx_left > 0) {
unsigned int entry = cur_rx % NUM_RX_DESC; unsigned int entry = cur_rx % NUM_RX_DESC;
struct RxDesc *desc = tp->RxDescArray + entry;
u32 status; u32 status;
rmb(); rmb();
status = le32_to_cpu(tp->RxDescArray[entry].opts1); status = le32_to_cpu(desc->opts1);
if (status & DescOwn) if (status & DescOwn)
break; break;
if (status & RxRES) { if (status & RxRES) {
printk(KERN_INFO "%s: Rx ERROR!!!\n", dev->name); printk(KERN_INFO "%s: Rx ERROR. status = %08x\n",
dev->name, status);
tp->stats.rx_errors++; tp->stats.rx_errors++;
if (status & (RxRWT | RxRUNT)) if (status & (RxRWT | RxRUNT))
tp->stats.rx_length_errors++; tp->stats.rx_length_errors++;
if (status & RxCRC) if (status & RxCRC)
tp->stats.rx_crc_errors++; tp->stats.rx_crc_errors++;
rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
} else { } else {
struct RxDesc *desc = tp->RxDescArray + entry;
struct sk_buff *skb = tp->Rx_skbuff[entry]; struct sk_buff *skb = tp->Rx_skbuff[entry];
int pkt_size = (status & 0x00001FFF) - 4; int pkt_size = (status & 0x00001FFF) - 4;
void (*pci_action)(struct pci_dev *, dma_addr_t, void (*pci_action)(struct pci_dev *, dma_addr_t,
size_t, int) = pci_dma_sync_single_for_device; size_t, int) = pci_dma_sync_single_for_device;
/*
* The driver does not support incoming fragmented
* frames. They are seen as a symptom of over-mtu
* sized frames.
*/
if (unlikely(rtl8169_fragmented_frame(status))) {
tp->stats.rx_dropped++;
tp->stats.rx_length_errors++;
rtl8169_mark_to_asic(desc, tp->rx_buf_sz);
goto move_on;
}
rtl8169_rx_csum(skb, desc); rtl8169_rx_csum(skb, desc);
pci_dma_sync_single_for_cpu(tp->pci_dev, pci_dma_sync_single_for_cpu(tp->pci_dev,
...@@ -2224,7 +2243,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp, ...@@ -2224,7 +2243,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
tp->stats.rx_bytes += pkt_size; tp->stats.rx_bytes += pkt_size;
tp->stats.rx_packets++; tp->stats.rx_packets++;
} }
move_on:
cur_rx++; cur_rx++;
rx_left--; rx_left--;
} }
......
...@@ -100,35 +100,8 @@ static int sh_debug; /* Debug flag */ ...@@ -100,35 +100,8 @@ static int sh_debug; /* Debug flag */
#define SHAPER_BANNER "CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n" #define SHAPER_BANNER "CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n"
/*
* Locking
*/
static int shaper_lock(struct shaper *sh)
{
/*
* Lock in an interrupt must fail
*/
while (test_and_set_bit(0, &sh->locked))
{
if (!in_interrupt())
sleep_on(&sh->wait_queue);
else
return 0;
}
return 1;
}
static void shaper_kick(struct shaper *sh); static void shaper_kick(struct shaper *sh);
static void shaper_unlock(struct shaper *sh)
{
clear_bit(0, &sh->locked);
wake_up(&sh->wait_queue);
shaper_kick(sh);
}
/* /*
* Compute clocks on a buffer * Compute clocks on a buffer
*/ */
...@@ -157,17 +130,15 @@ static void shaper_setspeed(struct shaper *shaper, int bitspersec) ...@@ -157,17 +130,15 @@ static void shaper_setspeed(struct shaper *shaper, int bitspersec)
* Throw a frame at a shaper. * Throw a frame at a shaper.
*/ */
static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct shaper *shaper = dev->priv;
struct sk_buff *ptr; struct sk_buff *ptr;
/* if (down_trylock(&shaper->sem))
* Get ready to work on this shaper. Lock may fail if its return -1;
* an interrupt and locked.
*/
if(!shaper_lock(shaper))
return -1;
ptr=shaper->sendq.prev; ptr=shaper->sendq.prev;
/* /*
...@@ -260,7 +231,8 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb) ...@@ -260,7 +231,8 @@ static int shaper_qframe(struct shaper *shaper, struct sk_buff *skb)
dev_kfree_skb(ptr); dev_kfree_skb(ptr);
shaper->stats.collisions++; shaper->stats.collisions++;
} }
shaper_unlock(shaper); shaper_kick(shaper);
up(&shaper->sem);
return 0; return 0;
} }
...@@ -297,8 +269,13 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb) ...@@ -297,8 +269,13 @@ static void shaper_queue_xmit(struct shaper *shaper, struct sk_buff *skb)
static void shaper_timer(unsigned long data) static void shaper_timer(unsigned long data)
{ {
struct shaper *sh=(struct shaper *)data; struct shaper *shaper = (struct shaper *)data;
shaper_kick(sh);
if (!down_trylock(&shaper->sem)) {
shaper_kick(shaper);
up(&shaper->sem);
} else
mod_timer(&shaper->timer, jiffies);
} }
/* /*
...@@ -310,19 +287,6 @@ static void shaper_kick(struct shaper *shaper) ...@@ -310,19 +287,6 @@ static void shaper_kick(struct shaper *shaper)
{ {
struct sk_buff *skb; struct sk_buff *skb;
/*
* Shaper unlock will kick
*/
if (test_and_set_bit(0, &shaper->locked))
{
if(sh_debug)
printk("Shaper locked.\n");
mod_timer(&shaper->timer, jiffies);
return;
}
/* /*
* Walk the list (may be empty) * Walk the list (may be empty)
*/ */
...@@ -364,8 +328,6 @@ static void shaper_kick(struct shaper *shaper) ...@@ -364,8 +328,6 @@ static void shaper_kick(struct shaper *shaper)
if(skb!=NULL) if(skb!=NULL)
mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock); mod_timer(&shaper->timer, SHAPERCB(skb)->shapeclock);
clear_bit(0, &shaper->locked);
} }
...@@ -376,14 +338,12 @@ static void shaper_kick(struct shaper *shaper) ...@@ -376,14 +338,12 @@ static void shaper_kick(struct shaper *shaper)
static void shaper_flush(struct shaper *shaper) static void shaper_flush(struct shaper *shaper)
{ {
struct sk_buff *skb; struct sk_buff *skb;
if(!shaper_lock(shaper))
{ down(&shaper->sem);
printk(KERN_ERR "shaper: shaper_flush() called by an irq!\n");
return;
}
while((skb=skb_dequeue(&shaper->sendq))!=NULL) while((skb=skb_dequeue(&shaper->sendq))!=NULL)
dev_kfree_skb(skb); dev_kfree_skb(skb);
shaper_unlock(shaper); shaper_kick(shaper);
up(&shaper->sem);
} }
/* /*
...@@ -426,13 +386,6 @@ static int shaper_close(struct net_device *dev) ...@@ -426,13 +386,6 @@ static int shaper_close(struct net_device *dev)
* ARP and other resolutions and not before. * ARP and other resolutions and not before.
*/ */
static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct shaper *sh=dev->priv;
return shaper_qframe(sh, skb);
}
static struct net_device_stats *shaper_get_stats(struct net_device *dev) static struct net_device_stats *shaper_get_stats(struct net_device *dev)
{ {
struct shaper *sh=dev->priv; struct shaper *sh=dev->priv;
...@@ -623,7 +576,6 @@ static void shaper_init_priv(struct net_device *dev) ...@@ -623,7 +576,6 @@ static void shaper_init_priv(struct net_device *dev)
init_timer(&sh->timer); init_timer(&sh->timer);
sh->timer.function=shaper_timer; sh->timer.function=shaper_timer;
sh->timer.data=(unsigned long)sh; sh->timer.data=(unsigned long)sh;
init_waitqueue_head(&sh->wait_queue);
} }
/* /*
......
/* /*
* CompactPCI Hot Plug Driver * CompactPCI Hot Plug Driver
* *
* Copyright (C) 2002 SOMA Networks, Inc. * Copyright (C) 2002,2005 SOMA Networks, Inc.
* Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2001 IBM Corp. * Copyright (C) 2001 IBM Corp.
* *
...@@ -45,10 +45,10 @@ ...@@ -45,10 +45,10 @@
#define dbg(format, arg...) \ #define dbg(format, arg...) \
do { \ do { \
if(cpci_debug) \ if (cpci_debug) \
printk (KERN_DEBUG "%s: " format "\n", \ printk (KERN_DEBUG "%s: " format "\n", \
MY_NAME , ## arg); \ MY_NAME , ## arg); \
} while(0) } while (0)
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
...@@ -111,10 +111,8 @@ enable_slot(struct hotplug_slot *hotplug_slot) ...@@ -111,10 +111,8 @@ enable_slot(struct hotplug_slot *hotplug_slot)
dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
if(controller->ops->set_power) { if (controller->ops->set_power)
retval = controller->ops->set_power(slot, 1); retval = controller->ops->set_power(slot, 1);
}
return retval; return retval;
} }
...@@ -126,37 +124,41 @@ disable_slot(struct hotplug_slot *hotplug_slot) ...@@ -126,37 +124,41 @@ disable_slot(struct hotplug_slot *hotplug_slot)
dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
down_write(&list_rwsem);
/* Unconfigure device */ /* Unconfigure device */
dbg("%s - unconfiguring slot %s", dbg("%s - unconfiguring slot %s",
__FUNCTION__, slot->hotplug_slot->name); __FUNCTION__, slot->hotplug_slot->name);
if((retval = cpci_unconfigure_slot(slot))) { if ((retval = cpci_unconfigure_slot(slot))) {
err("%s - could not unconfigure slot %s", err("%s - could not unconfigure slot %s",
__FUNCTION__, slot->hotplug_slot->name); __FUNCTION__, slot->hotplug_slot->name);
return retval; goto disable_error;
} }
dbg("%s - finished unconfiguring slot %s", dbg("%s - finished unconfiguring slot %s",
__FUNCTION__, slot->hotplug_slot->name); __FUNCTION__, slot->hotplug_slot->name);
/* Clear EXT (by setting it) */ /* Clear EXT (by setting it) */
if(cpci_clear_ext(slot)) { if (cpci_clear_ext(slot)) {
err("%s - could not clear EXT for slot %s", err("%s - could not clear EXT for slot %s",
__FUNCTION__, slot->hotplug_slot->name); __FUNCTION__, slot->hotplug_slot->name);
retval = -ENODEV; retval = -ENODEV;
goto disable_error;
} }
cpci_led_on(slot); cpci_led_on(slot);
if(controller->ops->set_power) { if (controller->ops->set_power)
retval = controller->ops->set_power(slot, 0); if ((retval = controller->ops->set_power(slot, 0)))
} goto disable_error;
if(update_adapter_status(slot->hotplug_slot, 0)) { if (update_adapter_status(slot->hotplug_slot, 0))
warn("failure to update adapter file"); warn("failure to update adapter file");
}
if(slot->extracting) { if (slot->extracting) {
slot->extracting = 0; slot->extracting = 0;
atomic_dec(&extracting); atomic_dec(&extracting);
} }
disable_error:
up_write(&list_rwsem);
return retval; return retval;
} }
...@@ -165,9 +167,8 @@ cpci_get_power_status(struct slot *slot) ...@@ -165,9 +167,8 @@ cpci_get_power_status(struct slot *slot)
{ {
u8 power = 1; u8 power = 1;
if(controller->ops->get_power) { if (controller->ops->get_power)
power = controller->ops->get_power(slot); power = controller->ops->get_power(slot);
}
return power; return power;
} }
...@@ -237,9 +238,8 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) ...@@ -237,9 +238,8 @@ cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
int status = -ENOMEM; int status = -ENOMEM;
int i; int i;
if(!(controller && bus)) { if (!(controller && bus))
return -ENODEV; return -ENODEV;
}
/* /*
* Create a structure for each slot, and register that slot * Create a structure for each slot, and register that slot
...@@ -316,32 +316,30 @@ int ...@@ -316,32 +316,30 @@ int
cpci_hp_unregister_bus(struct pci_bus *bus) cpci_hp_unregister_bus(struct pci_bus *bus)
{ {
struct slot *slot; struct slot *slot;
struct list_head *tmp; struct slot *tmp;
struct list_head *next; int status = 0;
int status;
down_write(&list_rwsem); down_write(&list_rwsem);
if(!slots) { if (!slots) {
up_write(&list_rwsem); up_write(&list_rwsem);
return -1; return -1;
} }
list_for_each_safe(tmp, next, &slot_list) { list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
slot = list_entry(tmp, struct slot, slot_list); if (slot->bus == bus) {
if(slot->bus == bus) { list_del(&slot->slot_list);
slots--;
dbg("deregistering slot %s", slot->hotplug_slot->name); dbg("deregistering slot %s", slot->hotplug_slot->name);
status = pci_hp_deregister(slot->hotplug_slot); status = pci_hp_deregister(slot->hotplug_slot);
if(status) { if (status) {
err("pci_hp_deregister failed with error %d", err("pci_hp_deregister failed with error %d",
status); status);
return status; break;
} }
list_del(&slot->slot_list);
slots--;
} }
} }
up_write(&list_rwsem); up_write(&list_rwsem);
return 0; return status;
} }
/* This is the interrupt mode interrupt handler */ /* This is the interrupt mode interrupt handler */
...@@ -351,7 +349,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs) ...@@ -351,7 +349,7 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
dbg("entered cpci_hp_intr"); dbg("entered cpci_hp_intr");
/* Check to see if it was our interrupt */ /* Check to see if it was our interrupt */
if((controller->irq_flags & SA_SHIRQ) && if ((controller->irq_flags & SA_SHIRQ) &&
!controller->ops->check_irq(controller->dev_id)) { !controller->ops->check_irq(controller->dev_id)) {
dbg("exited cpci_hp_intr, not our interrupt"); dbg("exited cpci_hp_intr, not our interrupt");
return IRQ_NONE; return IRQ_NONE;
...@@ -373,38 +371,30 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs) ...@@ -373,38 +371,30 @@ cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
* INS bits of the cold-inserted devices. * INS bits of the cold-inserted devices.
*/ */
static int static int
init_slots(void) init_slots(int clear_ins)
{ {
struct slot *slot; struct slot *slot;
struct list_head *tmp;
struct pci_dev* dev; struct pci_dev* dev;
dbg("%s - enter", __FUNCTION__); dbg("%s - enter", __FUNCTION__);
down_read(&list_rwsem); down_read(&list_rwsem);
if(!slots) { if (!slots) {
up_read(&list_rwsem); up_read(&list_rwsem);
return -1; return -1;
} }
list_for_each(tmp, &slot_list) { list_for_each_entry(slot, &slot_list, slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
dbg("%s - looking at slot %s", dbg("%s - looking at slot %s",
__FUNCTION__, slot->hotplug_slot->name); __FUNCTION__, slot->hotplug_slot->name);
if(cpci_check_and_clear_ins(slot)) { if (clear_ins && cpci_check_and_clear_ins(slot))
dbg("%s - cleared INS for slot %s", dbg("%s - cleared INS for slot %s",
__FUNCTION__, slot->hotplug_slot->name); __FUNCTION__, slot->hotplug_slot->name);
dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0)); dev = pci_get_slot(slot->bus, PCI_DEVFN(slot->number, 0));
if(dev) { if (dev) {
if(update_adapter_status(slot->hotplug_slot, 1)) { if (update_adapter_status(slot->hotplug_slot, 1))
warn("failure to update adapter file"); warn("failure to update adapter file");
} if (update_latch_status(slot->hotplug_slot, 1))
if(update_latch_status(slot->hotplug_slot, 1)) { warn("failure to update latch file");
warn("failure to update latch file"); slot->dev = dev;
}
slot->dev = dev;
} else {
err("%s - no driver attached to device in slot %s",
__FUNCTION__, slot->hotplug_slot->name);
}
} }
} }
up_read(&list_rwsem); up_read(&list_rwsem);
...@@ -416,26 +406,28 @@ static int ...@@ -416,26 +406,28 @@ static int
check_slots(void) check_slots(void)
{ {
struct slot *slot; struct slot *slot;
struct list_head *tmp;
int extracted; int extracted;
int inserted; int inserted;
u16 hs_csr; u16 hs_csr;
down_read(&list_rwsem); down_read(&list_rwsem);
if(!slots) { if (!slots) {
up_read(&list_rwsem); up_read(&list_rwsem);
err("no slots registered, shutting down"); err("no slots registered, shutting down");
return -1; return -1;
} }
extracted = inserted = 0; extracted = inserted = 0;
list_for_each(tmp, &slot_list) { list_for_each_entry(slot, &slot_list, slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
dbg("%s - looking at slot %s", dbg("%s - looking at slot %s",
__FUNCTION__, slot->hotplug_slot->name); __FUNCTION__, slot->hotplug_slot->name);
if(cpci_check_and_clear_ins(slot)) { if (cpci_check_and_clear_ins(slot)) {
/* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */ /*
if(slot->dev) { * Some broken hardware (e.g. PLX 9054AB) asserts
warn("slot %s already inserted", slot->hotplug_slot->name); * ENUM# twice...
*/
if (slot->dev) {
warn("slot %s already inserted",
slot->hotplug_slot->name);
inserted++; inserted++;
continue; continue;
} }
...@@ -452,7 +444,7 @@ check_slots(void) ...@@ -452,7 +444,7 @@ check_slots(void)
/* Configure device */ /* Configure device */
dbg("%s - configuring slot %s", dbg("%s - configuring slot %s",
__FUNCTION__, slot->hotplug_slot->name); __FUNCTION__, slot->hotplug_slot->name);
if(cpci_configure_slot(slot)) { if (cpci_configure_slot(slot)) {
err("%s - could not configure slot %s", err("%s - could not configure slot %s",
__FUNCTION__, slot->hotplug_slot->name); __FUNCTION__, slot->hotplug_slot->name);
continue; continue;
...@@ -465,13 +457,11 @@ check_slots(void) ...@@ -465,13 +457,11 @@ check_slots(void)
dbg("%s - slot %s HS_CSR (2) = %04x", dbg("%s - slot %s HS_CSR (2) = %04x",
__FUNCTION__, slot->hotplug_slot->name, hs_csr); __FUNCTION__, slot->hotplug_slot->name, hs_csr);
if(update_latch_status(slot->hotplug_slot, 1)) { if (update_latch_status(slot->hotplug_slot, 1))
warn("failure to update latch file"); warn("failure to update latch file");
}
if(update_adapter_status(slot->hotplug_slot, 1)) { if (update_adapter_status(slot->hotplug_slot, 1))
warn("failure to update adapter file"); warn("failure to update adapter file");
}
cpci_led_off(slot); cpci_led_off(slot);
...@@ -481,7 +471,7 @@ check_slots(void) ...@@ -481,7 +471,7 @@ check_slots(void)
__FUNCTION__, slot->hotplug_slot->name, hs_csr); __FUNCTION__, slot->hotplug_slot->name, hs_csr);
inserted++; inserted++;
} else if(cpci_check_ext(slot)) { } else if (cpci_check_ext(slot)) {
/* Process extraction request */ /* Process extraction request */
dbg("%s - slot %s extracted", dbg("%s - slot %s extracted",
__FUNCTION__, slot->hotplug_slot->name); __FUNCTION__, slot->hotplug_slot->name);
...@@ -491,27 +481,25 @@ check_slots(void) ...@@ -491,27 +481,25 @@ check_slots(void)
dbg("%s - slot %s HS_CSR = %04x", dbg("%s - slot %s HS_CSR = %04x",
__FUNCTION__, slot->hotplug_slot->name, hs_csr); __FUNCTION__, slot->hotplug_slot->name, hs_csr);
if(!slot->extracting) { if (!slot->extracting) {
if(update_latch_status(slot->hotplug_slot, 0)) { if (update_latch_status(slot->hotplug_slot, 0)) {
warn("failure to update latch file"); warn("failure to update latch file");
} }
atomic_inc(&extracting);
slot->extracting = 1; slot->extracting = 1;
atomic_inc(&extracting);
} }
extracted++; extracted++;
} else if(slot->extracting) { } else if (slot->extracting) {
hs_csr = cpci_get_hs_csr(slot); hs_csr = cpci_get_hs_csr(slot);
if(hs_csr == 0xffff) { if (hs_csr == 0xffff) {
/* /*
* Hmmm, we're likely hosed at this point, should we * Hmmm, we're likely hosed at this point, should we
* bother trying to tell the driver or not? * bother trying to tell the driver or not?
*/ */
err("card in slot %s was improperly removed", err("card in slot %s was improperly removed",
slot->hotplug_slot->name); slot->hotplug_slot->name);
if(update_adapter_status(slot->hotplug_slot, 0)) { if (update_adapter_status(slot->hotplug_slot, 0))
warn("failure to update adapter file"); warn("failure to update adapter file");
}
slot->extracting = 0; slot->extracting = 0;
atomic_dec(&extracting); atomic_dec(&extracting);
} }
...@@ -520,10 +508,9 @@ check_slots(void) ...@@ -520,10 +508,9 @@ check_slots(void)
up_read(&list_rwsem); up_read(&list_rwsem);
dbg("inserted=%d, extracted=%d, extracting=%d", dbg("inserted=%d, extracted=%d, extracting=%d",
inserted, extracted, atomic_read(&extracting)); inserted, extracted, atomic_read(&extracting));
if(inserted || extracted) { if (inserted || extracted)
return extracted; return extracted;
} else if (!atomic_read(&extracting)) {
else if(!atomic_read(&extracting)) {
err("cannot find ENUM# source, shutting down"); err("cannot find ENUM# source, shutting down");
return -1; return -1;
} }
...@@ -541,12 +528,12 @@ event_thread(void *data) ...@@ -541,12 +528,12 @@ event_thread(void *data)
unlock_kernel(); unlock_kernel();
dbg("%s - event thread started", __FUNCTION__); dbg("%s - event thread started", __FUNCTION__);
while(1) { while (1) {
dbg("event thread sleeping"); dbg("event thread sleeping");
down_interruptible(&event_semaphore); down_interruptible(&event_semaphore);
dbg("event thread woken, thread_finished = %d", dbg("event thread woken, thread_finished = %d",
thread_finished); thread_finished);
if(thread_finished || signal_pending(current)) if (thread_finished || signal_pending(current))
break; break;
do { do {
rc = check_slots(); rc = check_slots();
...@@ -558,7 +545,9 @@ event_thread(void *data) ...@@ -558,7 +545,9 @@ event_thread(void *data)
thread_finished = 1; thread_finished = 1;
break; break;
} }
} while(atomic_read(&extracting) != 0); } while (atomic_read(&extracting) && !thread_finished);
if (thread_finished)
break;
/* Re-enable ENUM# interrupt */ /* Re-enable ENUM# interrupt */
dbg("%s - re-enabling irq", __FUNCTION__); dbg("%s - re-enabling irq", __FUNCTION__);
...@@ -579,21 +568,21 @@ poll_thread(void *data) ...@@ -579,21 +568,21 @@ poll_thread(void *data)
daemonize("cpci_hp_polld"); daemonize("cpci_hp_polld");
unlock_kernel(); unlock_kernel();
while(1) { while (1) {
if(thread_finished || signal_pending(current)) if (thread_finished || signal_pending(current))
break; break;
if(controller->ops->query_enum()) { if (controller->ops->query_enum()) {
do { do {
rc = check_slots(); rc = check_slots();
if(rc > 0) { if (rc > 0) {
/* Give userspace a chance to handle extraction */ /* Give userspace a chance to handle extraction */
msleep(500); msleep(500);
} else if(rc < 0) { } else if (rc < 0) {
dbg("%s - error checking slots", __FUNCTION__); dbg("%s - error checking slots", __FUNCTION__);
thread_finished = 1; thread_finished = 1;
break; break;
} }
} while(atomic_read(&extracting) != 0); } while (atomic_read(&extracting) && !thread_finished);
} }
msleep(100); msleep(100);
} }
...@@ -612,12 +601,11 @@ cpci_start_thread(void) ...@@ -612,12 +601,11 @@ cpci_start_thread(void)
init_MUTEX_LOCKED(&thread_exit); init_MUTEX_LOCKED(&thread_exit);
thread_finished = 0; thread_finished = 0;
if(controller->irq) { if (controller->irq)
pid = kernel_thread(event_thread, NULL, 0); pid = kernel_thread(event_thread, NULL, 0);
} else { else
pid = kernel_thread(poll_thread, NULL, 0); pid = kernel_thread(poll_thread, NULL, 0);
} if (pid < 0) {
if(pid < 0) {
err("Can't start up our thread"); err("Can't start up our thread");
return -1; return -1;
} }
...@@ -630,9 +618,8 @@ cpci_stop_thread(void) ...@@ -630,9 +618,8 @@ cpci_stop_thread(void)
{ {
thread_finished = 1; thread_finished = 1;
dbg("thread finish command given"); dbg("thread finish command given");
if(controller->irq) { if (controller->irq)
up(&event_semaphore); up(&event_semaphore);
}
dbg("wait for thread to exit"); dbg("wait for thread to exit");
down(&thread_exit); down(&thread_exit);
} }
...@@ -642,45 +629,67 @@ cpci_hp_register_controller(struct cpci_hp_controller *new_controller) ...@@ -642,45 +629,67 @@ cpci_hp_register_controller(struct cpci_hp_controller *new_controller)
{ {
int status = 0; int status = 0;
if(!controller) { if (controller)
controller = new_controller; return -1;
if(controller->irq) { if (!(new_controller && new_controller->ops))
if(request_irq(controller->irq, return -EINVAL;
cpci_hp_intr, if (new_controller->irq) {
controller->irq_flags, if (!(new_controller->ops->enable_irq &&
MY_NAME, controller->dev_id)) { new_controller->ops->disable_irq))
err("Can't get irq %d for the hotplug cPCI controller", controller->irq); status = -EINVAL;
status = -ENODEV; if (request_irq(new_controller->irq,
} cpci_hp_intr,
dbg("%s - acquired controller irq %d", __FUNCTION__, new_controller->irq_flags,
controller->irq); MY_NAME,
new_controller->dev_id)) {
err("Can't get irq %d for the hotplug cPCI controller",
new_controller->irq);
status = -ENODEV;
} }
} else { dbg("%s - acquired controller irq %d",
err("cPCI hotplug controller already registered"); __FUNCTION__, new_controller->irq);
status = -1;
} }
if (!status)
controller = new_controller;
return status; return status;
} }
static void
cleanup_slots(void)
{
struct slot *slot;
struct slot *tmp;
/*
* Unregister all of our slots with the pci_hotplug subsystem,
* and free up all memory that we had allocated.
*/
down_write(&list_rwsem);
if (!slots)
goto cleanup_null;
list_for_each_entry_safe(slot, tmp, &slot_list, slot_list) {
list_del(&slot->slot_list);
pci_hp_deregister(slot->hotplug_slot);
}
cleanup_null:
up_write(&list_rwsem);
return;
}
int int
cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller) cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
{ {
int status = 0; int status = 0;
if(controller) { if (controller) {
if(atomic_read(&extracting) != 0) { if (!thread_finished)
return -EBUSY;
}
if(!thread_finished) {
cpci_stop_thread(); cpci_stop_thread();
} if (controller->irq)
if(controller->irq) {
free_irq(controller->irq, controller->dev_id); free_irq(controller->irq, controller->dev_id);
}
controller = NULL; controller = NULL;
} else { cleanup_slots();
} else
status = -ENODEV; status = -ENODEV;
}
return status; return status;
} }
...@@ -691,32 +700,28 @@ cpci_hp_start(void) ...@@ -691,32 +700,28 @@ cpci_hp_start(void)
int status; int status;
dbg("%s - enter", __FUNCTION__); dbg("%s - enter", __FUNCTION__);
if(!controller) { if (!controller)
return -ENODEV; return -ENODEV;
}
down_read(&list_rwsem); down_read(&list_rwsem);
if(list_empty(&slot_list)) { if (list_empty(&slot_list)) {
up_read(&list_rwsem); up_read(&list_rwsem);
return -ENODEV; return -ENODEV;
} }
up_read(&list_rwsem); up_read(&list_rwsem);
if(first) { status = init_slots(first);
status = init_slots(); if (first)
if(status) {
return status;
}
first = 0; first = 0;
} if (status)
return status;
status = cpci_start_thread(); status = cpci_start_thread();
if(status) { if (status)
return status; return status;
}
dbg("%s - thread started", __FUNCTION__); dbg("%s - thread started", __FUNCTION__);
if(controller->irq) { if (controller->irq) {
/* Start enum interrupt processing */ /* Start enum interrupt processing */
dbg("%s - enabling irq", __FUNCTION__); dbg("%s - enabling irq", __FUNCTION__);
controller->ops->enable_irq(); controller->ops->enable_irq();
...@@ -728,13 +733,9 @@ cpci_hp_start(void) ...@@ -728,13 +733,9 @@ cpci_hp_start(void)
int int
cpci_hp_stop(void) cpci_hp_stop(void)
{ {
if(!controller) { if (!controller)
return -ENODEV; return -ENODEV;
} if (controller->irq) {
if(atomic_read(&extracting) != 0) {
return -EBUSY;
}
if(controller->irq) {
/* Stop enum interrupt processing */ /* Stop enum interrupt processing */
dbg("%s - disabling irq", __FUNCTION__); dbg("%s - disabling irq", __FUNCTION__);
controller->ops->disable_irq(); controller->ops->disable_irq();
...@@ -743,34 +744,6 @@ cpci_hp_stop(void) ...@@ -743,34 +744,6 @@ cpci_hp_stop(void)
return 0; return 0;
} }
static void __exit
cleanup_slots(void)
{
struct list_head *tmp;
struct slot *slot;
/*
* Unregister all of our slots with the pci_hotplug subsystem,
* and free up all memory that we had allocated.
*/
down_write(&list_rwsem);
if(!slots) {
goto null_cleanup;
}
list_for_each(tmp, &slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
list_del(&slot->slot_list);
pci_hp_deregister(slot->hotplug_slot);
kfree(slot->hotplug_slot->info);
kfree(slot->hotplug_slot->name);
kfree(slot->hotplug_slot);
kfree(slot);
}
null_cleanup:
up_write(&list_rwsem);
return;
}
int __init int __init
cpci_hotplug_init(int debug) cpci_hotplug_init(int debug)
{ {
...@@ -784,7 +757,8 @@ cpci_hotplug_exit(void) ...@@ -784,7 +757,8 @@ cpci_hotplug_exit(void)
/* /*
* Clean everything up. * Clean everything up.
*/ */
cleanup_slots(); cpci_hp_stop();
cpci_hp_unregister_controller(controller);
} }
EXPORT_SYMBOL_GPL(cpci_hp_register_controller); EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
......
/* /*
* CompactPCI Hot Plug Driver PCI functions * CompactPCI Hot Plug Driver PCI functions
* *
* Copyright (C) 2002 by SOMA Networks, Inc. * Copyright (C) 2002,2005 by SOMA Networks, Inc.
* *
* All rights reserved. * All rights reserved.
* *
...@@ -38,10 +38,10 @@ extern int cpci_debug; ...@@ -38,10 +38,10 @@ extern int cpci_debug;
#define dbg(format, arg...) \ #define dbg(format, arg...) \
do { \ do { \
if(cpci_debug) \ if (cpci_debug) \
printk (KERN_DEBUG "%s: " format "\n", \ printk (KERN_DEBUG "%s: " format "\n", \
MY_NAME , ## arg); \ MY_NAME , ## arg); \
} while(0) } while (0)
#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg)
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
...@@ -57,16 +57,15 @@ u8 cpci_get_attention_status(struct slot* slot) ...@@ -57,16 +57,15 @@ u8 cpci_get_attention_status(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return 0; return 0;
}
if(pci_bus_read_config_word(slot->bus, if (pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return 0; return 0;
}
return hs_csr & 0x0008 ? 1 : 0; return hs_csr & 0x0008 ? 1 : 0;
} }
...@@ -78,27 +77,22 @@ int cpci_set_attention_status(struct slot* slot, int status) ...@@ -78,27 +77,22 @@ int cpci_set_attention_status(struct slot* slot, int status)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return 0; return 0;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return 0; return 0;
} if (status)
if(status) {
hs_csr |= HS_CSR_LOO; hs_csr |= HS_CSR_LOO;
} else { else
hs_csr &= ~HS_CSR_LOO; hs_csr &= ~HS_CSR_LOO;
} if (pci_bus_write_config_word(slot->bus,
if(pci_bus_write_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
hs_csr)) { hs_csr))
return 0; return 0;
}
return 1; return 1;
} }
...@@ -110,16 +104,13 @@ u16 cpci_get_hs_csr(struct slot* slot) ...@@ -110,16 +104,13 @@ u16 cpci_get_hs_csr(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return 0xFFFF; return 0xFFFF;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return 0xFFFF; return 0xFFFF;
}
return hs_csr; return hs_csr;
} }
...@@ -132,24 +123,22 @@ int cpci_check_and_clear_ins(struct slot* slot) ...@@ -132,24 +123,22 @@ int cpci_check_and_clear_ins(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return 0; return 0;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return 0; return 0;
} if (hs_csr & HS_CSR_INS) {
if(hs_csr & HS_CSR_INS) {
/* Clear INS (by setting it) */ /* Clear INS (by setting it) */
if(pci_bus_write_config_word(slot->bus, if (pci_bus_write_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
hs_csr)) { hs_csr))
ins = 0; ins = 0;
} else
ins = 1; ins = 1;
} }
return ins; return ins;
} }
...@@ -163,18 +152,15 @@ int cpci_check_ext(struct slot* slot) ...@@ -163,18 +152,15 @@ int cpci_check_ext(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return 0; return 0;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return 0; return 0;
} if (hs_csr & HS_CSR_EXT)
if(hs_csr & HS_CSR_EXT) {
ext = 1; ext = 1;
}
return ext; return ext;
} }
...@@ -186,23 +172,20 @@ int cpci_clear_ext(struct slot* slot) ...@@ -186,23 +172,20 @@ int cpci_clear_ext(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return -ENODEV; return -ENODEV;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return -ENODEV; return -ENODEV;
} if (hs_csr & HS_CSR_EXT) {
if(hs_csr & HS_CSR_EXT) {
/* Clear EXT (by setting it) */ /* Clear EXT (by setting it) */
if(pci_bus_write_config_word(slot->bus, if (pci_bus_write_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
hs_csr)) { hs_csr))
return -ENODEV; return -ENODEV;
}
} }
return 0; return 0;
} }
...@@ -215,18 +198,16 @@ int cpci_led_on(struct slot* slot) ...@@ -215,18 +198,16 @@ int cpci_led_on(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return -ENODEV; return -ENODEV;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return -ENODEV; return -ENODEV;
} if ((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
hs_csr |= HS_CSR_LOO; hs_csr |= HS_CSR_LOO;
if(pci_bus_write_config_word(slot->bus, if (pci_bus_write_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
hs_csr)) { hs_csr)) {
...@@ -246,18 +227,16 @@ int cpci_led_off(struct slot* slot) ...@@ -246,18 +227,16 @@ int cpci_led_off(struct slot* slot)
hs_cap = pci_bus_find_capability(slot->bus, hs_cap = pci_bus_find_capability(slot->bus,
slot->devfn, slot->devfn,
PCI_CAP_ID_CHSWP); PCI_CAP_ID_CHSWP);
if(!hs_cap) { if (!hs_cap)
return -ENODEV; return -ENODEV;
} if (pci_bus_read_config_word(slot->bus,
if(pci_bus_read_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
&hs_csr)) { &hs_csr))
return -ENODEV; return -ENODEV;
} if (hs_csr & HS_CSR_LOO) {
if(hs_csr & HS_CSR_LOO) {
hs_csr &= ~HS_CSR_LOO; hs_csr &= ~HS_CSR_LOO;
if(pci_bus_write_config_word(slot->bus, if (pci_bus_write_config_word(slot->bus,
slot->devfn, slot->devfn,
hs_cap + 2, hs_cap + 2,
hs_csr)) { hs_csr)) {
...@@ -274,19 +253,6 @@ int cpci_led_off(struct slot* slot) ...@@ -274,19 +253,6 @@ int cpci_led_off(struct slot* slot)
* Device configuration functions * Device configuration functions
*/ */
static void cpci_enable_device(struct pci_dev *dev)
{
struct pci_bus *bus;
pci_enable_device(dev);
if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
bus = dev->subordinate;
list_for_each_entry(dev, &bus->devices, bus_list) {
cpci_enable_device(dev);
}
}
}
int cpci_configure_slot(struct slot* slot) int cpci_configure_slot(struct slot* slot)
{ {
unsigned char busnr; unsigned char busnr;
...@@ -294,14 +260,14 @@ int cpci_configure_slot(struct slot* slot) ...@@ -294,14 +260,14 @@ int cpci_configure_slot(struct slot* slot)
dbg("%s - enter", __FUNCTION__); dbg("%s - enter", __FUNCTION__);
if(slot->dev == NULL) { if (slot->dev == NULL) {
dbg("pci_dev null, finding %02x:%02x:%x", dbg("pci_dev null, finding %02x:%02x:%x",
slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn)); slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
slot->dev = pci_find_slot(slot->bus->number, slot->devfn); slot->dev = pci_get_slot(slot->bus, slot->devfn);
} }
/* Still NULL? Well then scan for it! */ /* Still NULL? Well then scan for it! */
if(slot->dev == NULL) { if (slot->dev == NULL) {
int n; int n;
dbg("pci_dev still null"); dbg("pci_dev still null");
...@@ -311,10 +277,10 @@ int cpci_configure_slot(struct slot* slot) ...@@ -311,10 +277,10 @@ int cpci_configure_slot(struct slot* slot)
*/ */
n = pci_scan_slot(slot->bus, slot->devfn); n = pci_scan_slot(slot->bus, slot->devfn);
dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n); dbg("%s: pci_scan_slot returned %d", __FUNCTION__, n);
if(n > 0) if (n > 0)
pci_bus_add_devices(slot->bus); pci_bus_add_devices(slot->bus);
slot->dev = pci_find_slot(slot->bus->number, slot->devfn); slot->dev = pci_get_slot(slot->bus, slot->devfn);
if(slot->dev == NULL) { if (slot->dev == NULL) {
err("Could not find PCI device for slot %02x", slot->number); err("Could not find PCI device for slot %02x", slot->number);
return 1; return 1;
} }
...@@ -329,8 +295,6 @@ int cpci_configure_slot(struct slot* slot) ...@@ -329,8 +295,6 @@ int cpci_configure_slot(struct slot* slot)
pci_bus_assign_resources(slot->dev->bus); pci_bus_assign_resources(slot->dev->bus);
cpci_enable_device(slot->dev);
dbg("%s - exit", __FUNCTION__); dbg("%s - exit", __FUNCTION__);
return 0; return 0;
} }
...@@ -341,15 +305,15 @@ int cpci_unconfigure_slot(struct slot* slot) ...@@ -341,15 +305,15 @@ int cpci_unconfigure_slot(struct slot* slot)
struct pci_dev *dev; struct pci_dev *dev;
dbg("%s - enter", __FUNCTION__); dbg("%s - enter", __FUNCTION__);
if(!slot->dev) { if (!slot->dev) {
err("No device for slot %02x\n", slot->number); err("No device for slot %02x\n", slot->number);
return -ENODEV; return -ENODEV;
} }
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
dev = pci_find_slot(slot->bus->number, dev = pci_get_slot(slot->bus,
PCI_DEVFN(PCI_SLOT(slot->devfn), i)); PCI_DEVFN(PCI_SLOT(slot->devfn), i));
if(dev) { if (dev) {
pci_remove_bus_device(dev); pci_remove_bus_device(dev);
slot->dev = NULL; slot->dev = NULL;
} }
......
...@@ -1626,7 +1626,7 @@ int shpchprm_set_hpp( ...@@ -1626,7 +1626,7 @@ int shpchprm_set_hpp(
pci_bus->number = func->bus; pci_bus->number = func->bus;
devfn = PCI_DEVFN(func->device, func->function); devfn = PCI_DEVFN(func->device, func->function);
ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus);
if (ab) { if (ab) {
if (ab->_hpp) { if (ab->_hpp) {
...@@ -1681,7 +1681,7 @@ void shpchprm_enable_card( ...@@ -1681,7 +1681,7 @@ void shpchprm_enable_card(
| PCI_COMMAND_IO | PCI_COMMAND_MEMORY; | PCI_COMMAND_IO | PCI_COMMAND_MEMORY;
bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA; bcmd = bcommand = bcommand | PCI_BRIDGE_CTL_NO_ISA;
ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->bus); ab = find_acpi_bridge_by_bus(acpi_bridges_head, ctrl->seg, ctrl->slot_bus);
if (ab) { if (ab) {
if (ab->_hpp) { if (ab->_hpp) {
if (ab->_hpp->enable_perr) { if (ab->_hpp->enable_perr) {
......
...@@ -665,15 +665,6 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -665,15 +665,6 @@ static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
return ata_pci_init_one(pdev, port_info, n_ports); return ata_pci_init_one(pdev, port_info, n_ports);
} }
/**
* piix_init -
*
* LOCKING:
*
* RETURNS:
*
*/
static int __init piix_init(void) static int __init piix_init(void)
{ {
int rc; int rc;
...@@ -689,13 +680,6 @@ static int __init piix_init(void) ...@@ -689,13 +680,6 @@ static int __init piix_init(void)
return 0; return 0;
} }
/**
* piix_exit -
*
* LOCKING:
*
*/
static void __exit piix_exit(void) static void __exit piix_exit(void)
{ {
pci_unregister_driver(&piix_pci_driver); pci_unregister_driver(&piix_pci_driver);
......
此差异已折叠。
...@@ -947,7 +947,7 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf, ...@@ -947,7 +947,7 @@ unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
} }
/** /**
* ata_scsiop_noop - * ata_scsiop_noop - Command handler that simply returns success.
* @args: device IDENTIFY data / SCSI command of interest. * @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
* @buflen: Response buffer length. * @buflen: Response buffer length.
......
此差异已折叠。
...@@ -1197,6 +1197,7 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, ...@@ -1197,6 +1197,7 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
if (!starget) if (!starget)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
get_device(&starget->dev);
down(&shost->scan_mutex); down(&shost->scan_mutex);
res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
if (res != SCSI_SCAN_LUN_PRESENT) if (res != SCSI_SCAN_LUN_PRESENT)
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册