Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-elphel
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
linux-elphel
Commits
3590b827
Commit
3590b827
authored
Dec 27, 2016
by
Mikhail Karpenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Remove dev_dbg from IRQ and save state to buffer, read buffer from sysfs
parent
c6524ce2
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
82 additions
and
27 deletions
+82
-27
ahci_elphel.c
src/drivers/ata/ahci_elphel.c
+66
-23
ahci_elphel.h
src/drivers/ata/ahci_elphel.h
+16
-4
No files found.
src/drivers/ata/ahci_elphel.c
View file @
3590b827
...
...
@@ -179,6 +179,7 @@ static void process_timeout(unsigned long data)
struct
elphel_ahci_priv
*
dpriv
=
(
struct
elphel_ahci_priv
*
)
data
;
dev_err
(
dpriv
->
dev
,
"AHCI error: command execution timeout, LBA start = 0x%llx
\n
"
,
dpriv
->
lba_ptr
.
lba_write
);
set_dscope_tstamp
(
dpriv
,
TSTMP_CMD_SYS
);
set_flag
(
dpriv
,
START_EH
);
}
...
...
@@ -229,13 +230,28 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance)
/* handle interrupt from internal command */
host_irq_stat
=
readl
(
hpriv
->
mmio
+
HOST_IRQ_STAT
);
if
(
!
host_irq_stat
)
return
IRQ_NONE
;
dpriv
->
flags
&=
~
IRQ_SIMPLE
;
if
(
!
host_irq_stat
)
{
dev_err
(
dpriv
->
dev
,
"Spurious IRQ received, host_irq_stat = 0x%x
\n
"
,
host_irq_stat
);
// debug actions, check it one more time before exit
host_irq_stat
=
readl
(
hpriv
->
mmio
+
HOST_IRQ_STAT
);
if
(
!
host_irq_stat
)
{
return
IRQ_NONE
;
}
else
{
dev_err
(
dpriv
->
dev
,
"Spurious interrupt not confirmed, host_irq_stat = 0x%x, proceed to IRQ processing
\n
"
,
host_irq_stat
);
}
}
// dpriv->flags &= ~IRQ_SIMPLE;
reset_flag
(
dpriv
,
IRQ_SIMPLE
);
irq_stat
=
readl
(
port_mmio
+
PORT_IRQ_STAT
);
serror
=
readl
(
port_mmio
+
PORT_SCR_ERR
);
dev_dbg
(
host
->
dev
,
"irq_stat = 0x%x, host irq_stat = 0x%x, SErr = 0x%x
\n
"
,
irq_stat
,
host_irq_stat
,
serror
);
dpriv
->
datascope
.
reg_stat
[
REG_HOST_IS
]
=
host_irq_stat
;
dpriv
->
datascope
.
reg_stat
[
REG_PxIS
]
=
irq_stat
;
dpriv
->
datascope
.
reg_stat
[
REG_PxSERR
]
=
serror
;
dpriv
->
datascope
.
reg_stat
[
REG_PxIE
]
=
readl
(
port_mmio
+
PORT_IRQ_MASK
);
dpriv
->
datascope
.
reg_stat
[
IRQ_COUNTER
]
=
dpriv
->
datascope
.
reg_stat
[
IRQ_COUNTER
]
+
1
;
// dev_dbg(host->dev, "irq_stat = 0x%x, host irq_stat = 0x%x, SErr = 0x%x\n", irq_stat, host_irq_stat, serror);
if
(
unlikely
(
irq_stat
&
PORT_IRQ_ERROR
))
{
dpriv
->
eh
.
irq_stat
=
irq_stat
;
...
...
@@ -246,12 +262,14 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance)
writel
(
irq_stat
,
port_mmio
+
PORT_IRQ_STAT
);
writel
(
host_irq_stat
,
hpriv
->
mmio
+
HOST_IRQ_STAT
);
handled
=
IRQ_HANDLED
;
set_dscope_tstamp
(
dpriv
,
TSTMP_IRQ_MARK_1
);
/* check if this command timed out and charged error handler, do not schedule tasklet in this case as
* the processing will restart from error handler
*/
if
(
dpriv
->
flags
&
(
START_EH
|
WAIT_EH
))
{
// tell to EH that the command will be processed in normal way
set_dscope_tstamp
(
dpriv
,
TSTMP_IRQ_MARK_1
);
set_flag
(
dpriv
,
DELAYED_IRQ_RCVD
);
wake_up_interruptible
(
&
dpriv
->
eh
.
wait
);
}
else
{
...
...
@@ -261,6 +279,7 @@ static irqreturn_t elphel_irq_handler(int irq, void * dev_instance)
}
else
{
set_dscope_tstamp
(
dpriv
,
TSTMP_IRQ_SYS
);
dpriv
->
datascope
.
reg_stat
[
IRQ_COUNTER_SYS
]
=
dpriv
->
datascope
.
reg_stat
[
IRQ_COUNTER_SYS
]
+
1
;
/* pass handling to AHCI level and then decide if the resource should be freed */
handled
=
ahci_single_irq_intr
(
irq
,
dev_instance
);
...
...
@@ -295,8 +314,8 @@ void process_queue(unsigned long data)
}
// check if we can proceed - this was debug feature to fully stop cmd processing
//
if (dpriv->flags & (START_EH | WAIT_EH))
//
return;
if
(
dpriv
->
flags
&
(
START_EH
|
WAIT_EH
))
return
;
if
(
process_cmd
(
dpriv
)
==
0
)
{
finish_cmd
(
dpriv
);
...
...
@@ -1255,22 +1274,23 @@ void error_handler(struct elphel_ahci_priv *dpriv)
rc
=
wait_event_interruptible_timeout
(
dpriv
->
eh
.
wait
,
dpriv
->
flags
&
DELAYED_IRQ_RCVD
,
deadline
);
dev_warn
(
dpriv
->
dev
,
"wait_event_interruptible_timeout returned %ld
\n
"
,
rc
);
if
(
!
rc
)
{
/* interrupt has not been received after more than (DEFAULT_CMD_TIMEOUT + WAIT_IRQ_TIMEOUT) ms,
* try to recover the link using WAIT_IRQ_TIMEOUT value for next deadline
*/
deadline
=
jiffies
+
msecs_to_jiffies
(
WAIT_IRQ_TIMEOUT
);
rc
=
ap
->
ops
->
hardreset
(
link
,
&
class
,
deadline
);
if
(
!
rc
)
dev_err
(
dpriv
->
dev
,
"error: ahci_hardreset returned %ld
\n
"
,
rc
);
ata_port_wait_eh
(
ap
);
// here we assume that circbuf has not been overrun yet, prepare to repeat current command
dpriv
->
lba_ptr
.
wr_count
=
0
;
dpriv
->
curr_cmd
=
0
;
dpriv
->
max_data_sz
=
0
;
dpriv
->
curr_data_chunk
=
0
;
dpriv
->
curr_data_offset
=
0
;
reset_flag
(
dpriv
,
IRQ_SIMPLE
|
DISK_BUSY
|
PROC_CMD
|
START_EH
);
return
;
// reset_flag(dpriv, IRQ_SIMPLE | DISK_BUSY | PROC_CMD | START_EH);
// /* interrupt has not been received after more than (DEFAULT_CMD_TIMEOUT + WAIT_IRQ_TIMEOUT) ms,
// * try to recover the link using WAIT_IRQ_TIMEOUT value for next deadline
// */
// deadline = jiffies + msecs_to_jiffies(WAIT_IRQ_TIMEOUT);
// rc = ap->ops->hardreset(link, &class, deadline);
// if (!rc)
// dev_err(dpriv->dev, "error: ahci_hardreset returned %ld\n", rc);
// ata_port_wait_eh(ap);
//
// // here we assume that circbuf has not been overrun yet, prepare to repeat current command
// dpriv->lba_ptr.wr_count = 0;
// dpriv->curr_cmd = 0;
// dpriv->max_data_sz = 0;
// dpriv->curr_data_chunk = 0;
// dpriv->curr_data_offset = 0;
dev_dbg
(
dpriv
->
dev
,
"repeat command from slot (head_ptr): %u
\n
"
,
dpriv
->
head_ptr
);
// process_cmd(dpriv);
}
else
{
...
...
@@ -1295,6 +1315,7 @@ void error_handler(struct elphel_ahci_priv *dpriv)
}
}
/** This function is called during write test only */
static
void
invalidate_cache
(
struct
fvec
*
vect
)
{
__cpuc_flush_dcache_area
(
vect
->
iov_base
,
vect
->
iov_len
);
...
...
@@ -1546,6 +1567,7 @@ static void elphel_cmd_issue(struct ata_port *ap,///< device port for which the
dma_sync_single_for_device
(
ap
->
dev
,
pp
->
cmd_tbl_dma
,
AHCI_CMD_TBL_AR_SZ
,
DMA_TO_DEVICE
);
set_dscope_tstamp
(
dpriv
,
TSTMP_CMD_DRV
);
dpriv
->
datascope
.
reg_stat
[
CMD_SENT
]
=
dpriv
->
datascope
.
reg_stat
[
CMD_SENT
]
+
1
;
/* issue command */
writel
(
0x11
,
port_mmio
+
PORT_CMD
);
...
...
@@ -1559,6 +1581,8 @@ static int elphel_qc_defer(struct ata_queued_cmd *qc)
unsigned
long
irq_flags
;
struct
elphel_ahci_priv
*
dpriv
=
dev_get_dpriv
(
qc
->
ap
->
dev
);
dev_dbg
(
qc
->
ap
->
dev
,
"flags: %u
\n
"
,
dpriv
->
flags
);
/* First apply the usual rules */
ret
=
ata_std_qc_defer
(
qc
);
if
(
ret
!=
0
)
...
...
@@ -1701,7 +1725,7 @@ static ssize_t io_error_read(struct device *dev, struct device_attribute *attr,
return
sprintf
(
buff
,
"%u
\n
"
,
dpriv
->
io_error_flag
);
}
/** Reset statistics availability flag. This will indicat
ate that the current samples
is processed */
/** Reset statistics availability flag. This will indicat
e that the current sample
is processed */
static
ssize_t
stat_delay_write
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
const
char
*
buff
,
size_t
buff_sz
)
{
unsigned
long
data
;
...
...
@@ -1729,9 +1753,27 @@ static ssize_t stat_delay_read(struct device *dev, struct device_attribute *attr
return
scnprintf
(
buff
,
20
,
"%u
\n
"
,
data
);
}
static
ssize_t
reg_status_read
(
struct
device
*
dev
,
struct
device_attribute
*
attr
,
char
*
buff
)
{
int
i
;
ssize_t
cntr
;
unsigned
int
data
;
struct
elphel_ahci_priv
*
dpriv
=
dev_get_dpriv
(
dev
);
for
(
i
=
0
,
cntr
=
0
;
i
<
REG_NUM
;
i
++
)
{
if
((
i
%
8
)
==
0
&&
i
!=
0
)
cntr
+=
scnprintf
(
&
buff
[
cntr
],
PAGE_SIZE
-
cntr
-
1
,
"
\n
"
);
cntr
+=
scnprintf
(
&
buff
[
cntr
],
PAGE_SIZE
-
cntr
-
1
,
"0x%08x "
,
dpriv
->
datascope
.
reg_stat
[
i
]);
}
cntr
+=
scnprintf
(
&
buff
[
cntr
],
PAGE_SIZE
-
cntr
-
1
,
"
\n
"
);
return
cntr
;
}
static
DEVICE_ATTR
(
load_module
,
S_IWUSR
|
S_IWGRP
,
NULL
,
set_load_flag
);
static
DEVICE_ATTR
(
io_error
,
S_IRUSR
|
S_IRGRP
|
S_IROTH
,
io_error_read
,
NULL
);
static
DEVICE_ATTR
(
stat_irq_delay
,
S_IRUSR
|
S_IRGRP
|
S_IROTH
|
S_IWUSR
|
S_IWGRP
,
stat_delay_read
,
stat_delay_write
);
static
DEVICE_ATTR
(
reg_status
,
S_IRUSR
|
S_IRGRP
|
S_IROTH
,
reg_status_read
,
NULL
);
static
DEVICE_ATTR
(
SYSFS_AHCI_FNAME_WRITE
,
S_IWUSR
|
S_IWGRP
,
NULL
,
rawdev_write
);
static
DEVICE_ATTR
(
SYSFS_AHCI_FNAME_START
,
S_IRUSR
|
S_IRGRP
|
S_IROTH
|
S_IWUSR
|
S_IWGRP
,
lba_start_read
,
lba_start_write
);
static
DEVICE_ATTR
(
SYSFS_AHCI_FNAME_END
,
S_IRUSR
|
S_IRGRP
|
S_IROTH
|
S_IWUSR
|
S_IWGRP
,
lba_end_read
,
lba_end_write
);
...
...
@@ -1742,6 +1784,7 @@ static struct attribute *root_dev_attrs[] = {
&
dev_attr_load_module
.
attr
,
&
dev_attr_io_error
.
attr
,
&
dev_attr_stat_irq_delay
.
attr
,
&
dev_attr_reg_status
.
attr
,
&
dev_attr_SYSFS_AHCI_FNAME_WRITE
.
attr
,
&
dev_attr_SYSFS_AHCI_FNAME_START
.
attr
,
&
dev_attr_SYSFS_AHCI_FNAME_END
.
attr
,
...
...
src/drivers/ata/ahci_elphel.h
View file @
3590b827
...
...
@@ -63,20 +63,32 @@
#define EXCLUDE_REM 0 ///< Exclude REM buffer from total size calculation
#define SPEED_SAMPLES_NUM 5 ///< Maximum number of samples for disk recording speed measurement
#define DEFAULT_CMD_TIMEOUT 100 ///< Default timeout for commands, in ms
#define WAIT_IRQ_TIMEOUT
1
000 ///< Wait delayed interrupt for this amount of time, in ms
#define WAIT_IRQ_TIMEOUT
5
000 ///< Wait delayed interrupt for this amount of time, in ms
#define TSTMP_CMD_SYS 1 ///< command issued by system
#define TSTMP_CMD_DRV 2 ///< command issued by driver
#define TSTMP_IRQ_SYS 3 ///< irq processed by system
#define TSTMP_IRQ_DRV 4 ///< irq processed by driver
#define TSTMP_IRQ_MARK_1 5
enum
{
PORT_VS
=
0x70
,
///< vendor specific port address
PORT_TIMESTAMP_ADDR
=
0x78
///< datascope timestamp register
};
enum
{
REG_NUM
=
128
,
///< total number of DWs in status buffer
REG_HOST_IS
=
0
,
///< value of host IS register in data buffer
REG_PxIS
,
///< value of PxIS in data buffer
REG_PxIE
,
///< value of PxIE in data buffer
REG_PxSERR
,
///< value of PxSERR in data buffer
IRQ_COUNTER
,
///< interrupts counter for internal commands
IRQ_COUNTER_SYS
,
///< interrupts counter for system commands
CMD_SENT
///< number of commands sent
};
struct
datascope
{
void
__iomem
*
timestamp_reg
;
///< register in vendor specific address range (PxVS) where timestamp can be written
unsigned
int
cmd_cntr
;
///< command counter, its value can be found in timestamp (2 bits only)
unsigned
int
enable
;
///< enable/disable timestamps
void
__iomem
*
timestamp_reg
;
///< register in vendor specific address range (PxVS) where timestamp can be written
unsigned
int
cmd_cntr
;
///< command counter, its value can be found in timestamp (2 bits only)
unsigned
int
enable
;
///< enable/disable timestamps
uint32_t
reg_stat
[
REG_NUM
];
///< buffer for registers' status, filled in in IRQ
};
/** Data for error handler */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment