oxnas: add support for 2nd S-ATA port to sata_oxnas driver

similar to mv_sata, use nr-ports attribute from device tree.
import and adapt locking code from vendor GPL sources.
add dma controller handling, it may be used in future to avoid
full core resets similar to the vendor SDK's "progressive cleanup"
function.

this is still very dirty and aimed to first of all do things
quite exactly like the reference code. and it somehow works.
obviously there is lots of room for improvement :)

Signed-off-by: Daniel Golle <daniel@makrotopia.org>

SVN-Revision: 43598
This commit is contained in:
John Crispin 2014-12-10 15:51:07 +00:00
parent 1fa7c8587d
commit 9432cbd577
5 changed files with 686 additions and 87 deletions

View file

@ -26,6 +26,7 @@
sata@45900000 { sata@45900000 {
status = "okay"; status = "okay";
nr-ports = <2>;
}; };
nand@41000000 { nand@41000000 {

View file

@ -286,14 +286,15 @@
sata@45900000 { sata@45900000 {
compatible = "plxtech,nas782x-sata"; compatible = "plxtech,nas782x-sata";
/* port sgdma core */ /* ports dmactl sgdma */
reg = <0x45900000 0x100>, <0x459B0000 0x10>, <0x459E0000 0x2000>, reg = <0x45900000 0x20000>, <0x459A0000 0x40>, <0x459B0000 0x20>,
/* phy descriptors (optional) */ /* core phy descriptors (optional) */
<0x44900000 0x0C>, <0x50000000 0x1000>; <0x459E0000 0x2000>, <0x44900000 0x0C>, <0x50000000 0x1000>;
interrupts = <0 18 0x304>; interrupts = <0 18 0x304>;
clocks = <&stdclk 4>; clocks = <&stdclk 4>;
resets = <&rst 11>, <&rst 12>, <&rst 13>; resets = <&rst 11>, <&rst 12>, <&rst 13>;
reset-names = "sata", "link", "phy"; reset-names = "sata", "link", "phy";
nr-ports = <1>;
status = "disabled"; status = "disabled";
}; };

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,60 @@
Index: linux-3.18-rc7/drivers/ata/libata-core.c
===================================================================
--- linux-3.18-rc7.orig/drivers/ata/libata-core.c
+++ linux-3.18-rc7/drivers/ata/libata-core.c
@@ -1568,6 +1568,14 @@ unsigned ata_exec_internal_sg(struct ata
return AC_ERR_SYSTEM;
}
+ if (ap->ops->acquire_hw && !ap->ops->acquire_hw(ap->port_no, 0, 0)) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ if (!ap->ops->acquire_hw(ap->port_no, 1, (2*HZ))) {
+ return AC_ERR_TIMEOUT;
+ }
+ spin_lock_irqsave(ap->lock, flags);
+ }
+
/* initialize internal qc */
/* XXX: Tag 0 is used for drivers with legacy EH as some
@@ -4739,6 +4747,9 @@ static struct ata_queued_cmd *ata_qc_new
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
return NULL;
+ if (ap->ops->qc_new && ap->ops->qc_new(ap))
+ return NULL;
+
for (i = 0, tag = ap->last_tag + 1; i < max_queue; i++, tag++) {
tag = tag < max_queue ? tag : 0;
@@ -4805,6 +4816,8 @@ void ata_qc_free(struct ata_queued_cmd *
if (likely(ata_tag_valid(tag))) {
qc->tag = ATA_TAG_POISON;
clear_bit(tag, &ap->qc_allocated);
+ if (ap->ops->qc_free)
+ ap->ops->qc_free(qc);
}
}
Index: linux-3.18-rc7/include/linux/libata.h
===================================================================
--- linux-3.18-rc7.orig/include/linux/libata.h
+++ linux-3.18-rc7/include/linux/libata.h
@@ -884,6 +884,8 @@ struct ata_port_operations {
void (*qc_prep)(struct ata_queued_cmd *qc);
unsigned int (*qc_issue)(struct ata_queued_cmd *qc);
bool (*qc_fill_rtf)(struct ata_queued_cmd *qc);
+ int (*qc_new)(struct ata_port *ap);
+ void (*qc_free)(struct ata_queued_cmd *qc);
/*
* Configuration and exception handling
@@ -974,6 +976,8 @@ struct ata_port_operations {
void (*phy_reset)(struct ata_port *ap);
void (*eng_timeout)(struct ata_port *ap);
+ int (*acquire_hw)(int port_no, int may_sleep, int timeout_jiffies);
+
/*
* ->inherits must be the last field and all the preceding
* fields must be pointers.

View file

@ -0,0 +1,60 @@
Index: linux-3.18-rc7/drivers/ata/libata-core.c
===================================================================
--- linux-3.18-rc7.orig/drivers/ata/libata-core.c
+++ linux-3.18-rc7/drivers/ata/libata-core.c
@@ -1568,6 +1568,14 @@ unsigned ata_exec_internal_sg(struct ata
return AC_ERR_SYSTEM;
}
+ if (ap->ops->acquire_hw && !ap->ops->acquire_hw(ap->port_no, 0, 0)) {
+ spin_unlock_irqrestore(ap->lock, flags);
+ if (!ap->ops->acquire_hw(ap->port_no, 1, (2*HZ))) {
+ return AC_ERR_TIMEOUT;
+ }
+ spin_lock_irqsave(ap->lock, flags);
+ }
+
/* initialize internal qc */
/* XXX: Tag 0 is used for drivers with legacy EH as some
@@ -4739,6 +4747,9 @@ static struct ata_queued_cmd *ata_qc_new
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
return NULL;
+ if (ap->ops->qc_new && ap->ops->qc_new(ap))
+ return NULL;
+
for (i = 0, tag = ap->last_tag + 1; i < max_queue; i++, tag++) {
tag = tag < max_queue ? tag : 0;
@@ -4805,6 +4816,8 @@ void ata_qc_free(struct ata_queued_cmd *
if (likely(ata_tag_valid(tag))) {
qc->tag = ATA_TAG_POISON;
clear_bit(tag, &ap->qc_allocated);
+ if (ap->ops->qc_free)
+ ap->ops->qc_free(qc);
}
}
Index: linux-3.18-rc7/include/linux/libata.h
===================================================================
--- linux-3.18-rc7.orig/include/linux/libata.h
+++ linux-3.18-rc7/include/linux/libata.h
@@ -884,6 +884,8 @@ struct ata_port_operations {
void (*qc_prep)(struct ata_queued_cmd *qc);
unsigned int (*qc_issue)(struct ata_queued_cmd *qc);
bool (*qc_fill_rtf)(struct ata_queued_cmd *qc);
+ int (*qc_new)(struct ata_port *ap);
+ void (*qc_free)(struct ata_queued_cmd *qc);
/*
* Configuration and exception handling
@@ -974,6 +976,8 @@ struct ata_port_operations {
void (*phy_reset)(struct ata_port *ap);
void (*eng_timeout)(struct ata_port *ap);
+ int (*acquire_hw)(int port_no, int may_sleep, int timeout_jiffies);
+
/*
* ->inherits must be the last field and all the preceding
* fields must be pointers.