ahci: use ports implemented map instead of num_ports
PATCH v2 1/8 ahci: use ports implemented map instead of num_ports
From: Richard Gibbs <[email protected]>
The AHCI driver was incorrectly using the Capabilities register NP (number of ports) field to determine which ports to activate. This commit changes it to correctly use the PORTS_IMPL register as a port map.
---
v2: rebase to v2013.10-rc1
drivers/block/ahci.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/block/ahci.c +4 -0
@@ -119,6 +119,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)u32 tmp, cap_save, cmd;int i, j;volatile u8 *port_mmio; +u32 port_map;debug ("ahci_host_init: start\n" );
@@ -160,6 +161,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)#endif probe_ent->cap =readl (mmio +HOST_CAP ); probe_ent->port_map =readl (mmio +HOST_PORTS_IMPL ); + port_map = probe_ent->port_map; probe_ent->n_ports = (probe_ent->cap &0x1f ) +1 ; debug("cap 0x%x port_map 0x%x n_ports %d\n",
@@ -169,6 +171,8 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) probe_ent->n_ports =CONFIG_SYS_SCSI_MAX_SCSI_ID ;for (i =0 ; i < probe_ent->n_ports; i++) { +if (!(port_map & (1 << i))) +continue ; probe_ent->port[i].port_mmio =ahci_port_base ((u32 ) mmio, i); port_mmio = (u8 *) probe_ent->port[i].port_mmio;ahci_setup_port (&probe_ent->port[i], (unsigned long )mmio, i);
Signature · 1 line
1.8.1.2
PATCH v2 2/8 ahci: fix unaligned access
From: Rob Herring <[email protected]>
gcc 4.7 will generate unaligned accesses to local char arrays, so make them static to avoid that.
---
v2: make hdr const
drivers/block/ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/block/ahci.c +1 -1
@@ -610,7 +610,7 @@ static void dump_ataid(hd_driveid_t *ataid)*/ static int ata_scsiop_inquiry (ccb *pccb) { -u8 hdr[] = { +static const u8 hdr[] = {0 ,0 ,0x5 ,/* claim SPC-3 version compatibility */
Signature · 1 line
1.8.1.2
PATCH v2 3/8 ahci: fix memory leak in ata_scsiop_inquiry
In reply to Rob HerringFrom: Rob Herring <[email protected]>
This fixes a memory leak when scsi inquiry fails.
---
v2: rebase to v2013.10-rc1
drivers/block/ahci.c | 1 + 1 file changed, 1 insertion(+)
drivers/block/ahci.c +1 -0
@@ -643,6 +643,7 @@ static int ata_scsiop_inquiry(ccb *pccb)if (ahci_device_data_io (port, (u8 *) &fis,sizeof (fis), tmpid,sizeof (hd_driveid_t),0 )) {debug ("scsi_ahci: SCSI inquiry command failure.\n" ); +free (tmpid);return -EIO ; }
Signature · 1 line
1.8.1.2
PATCH v2 4/8 ahci: add defines for PORT_SCR_STAT register bits
In reply to Rob HerringFrom: Rob Herring <[email protected]>
Replace hard-coded register values with proper defines for PORT_SCR_STAT register.
---
v2: New patch
drivers/block/ahci.c | 5 +++-- include/ahci.h | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-)
drivers/block/ahci.c +3 -2
@@ -207,7 +207,8 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) j =0 ;while (j <WAIT_MS_LINKUP ) { tmp =readl (port_mmio +PORT_SCR_STAT ); -if ((tmp &0xf ) ==0x3 ) + tmp &=PORT_SCR_STAT_DET_MASK ; +if (tmp ==PORT_SCR_STAT_DET_PHYRDY )break ;udelay (1000 ); j++;
@@ -258,7 +259,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)/* register linkup ports */ tmp =readl (port_mmio +PORT_SCR_STAT );debug ("SATA port %d status: 0x%x\n" , i, tmp); -if ((tmp &0xf ) ==0x03 ) +if ((tmp &PORT_SCR_STAT_DET_MASK ) ==PORT_SCR_STAT_DET_PHYRDY ) probe_ent->link_port_map |= (0x01 << i); }
include/ahci.h +5 -0
@@ -87,6 +87,11 @@ | PORT_IRQ_DMAS_FIS | PORT_IRQ_PIOS_FIS \ | PORT_IRQ_D2H_REG_FIS +/* PORT_SCR_STAT bits */ +#define PORT_SCR_STAT_DET_MASK 0x3 +#define PORT_SCR_STAT_DET_COMINIT 0x1 +#define PORT_SCR_STAT_DET_PHYRDY 0x3 +/* PORT_CMD bits */ #define PORT_CMD_ATAPI (1 << 24)/* Device is ATAPI */ #define PORT_CMD_LIST_ON (1 << 15)/* cmd list DMA engine running */
Signature · 1 line
1.8.1.2
PATCH v2 5/8 ahci: move link bring-up handling to separate function
In reply to Rob HerringFrom: Rob Herring <[email protected]>
Move the link bring-up handling to a separate weak function in order to allow platforms to override it. This is needed on highbank platform which needs special phy handling.
---
v2:
- Use __weak attribute instead
- Fix comment formatting
- Use defines added in previous patch
drivers/block/ahci.c | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-)
drivers/block/ahci.c +25 -15
@@ -107,6 +107,27 @@ static int waiting_for_cmd_completed(volatile u8 *offset,return (i < timeout_msec) ?0 :-1 ; } +int __weak ahci_link_up (struct ahci_probe_ent *probe_ent,u8 port) +{ +u32 tmp; +int j =0 ; +u8 *port_mmio = (u8 *)probe_ent->port[port].port_mmio; + +/* +* Bring up SATA link. +* SATA link bringup time is usually less than 1 ms; only very +* rarely has it taken between 1-2 ms. Never seen it above 2 ms. +*/ +while (j <WAIT_MS_LINKUP ) { + tmp =readl (port_mmio +PORT_SCR_STAT ); + tmp &=PORT_SCR_STAT_DET_MASK ; +if (tmp ==PORT_SCR_STAT_DET_PHYRDY ) +return 0 ; +udelay (1000 ); + j++; + } +return 1 ; +}static int ahci_host_init (struct ahci_probe_ent *probe_ent) {
@@ -117,7 +138,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)#endif volatile u8 *mmio = (volatile u8 *)probe_ent->mmio_base;u32 tmp, cap_save, cmd; -int i, j; +int i, j, ret;volatile u8 *port_mmio;u32 port_map;
@@ -200,20 +221,9 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) cmd |=PORT_CMD_SPIN_UP ;writel_with_flush (cmd, port_mmio +PORT_CMD ); -/* Bring up SATA link. -* SATA link bringup time is usually less than 1 ms; only very -* rarely has it taken between 1-2 ms. Never seen it above 2 ms. -*/ - j =0 ; -while (j <WAIT_MS_LINKUP ) { - tmp =readl (port_mmio +PORT_SCR_STAT ); - tmp &=PORT_SCR_STAT_DET_MASK ; -if (tmp ==PORT_SCR_STAT_DET_PHYRDY ) -break ; -udelay (1000 ); - j++; - } -if (j ==WAIT_MS_LINKUP ) { +/* Bring up SATA link. */ + ret =ahci_link_up (probe_ent, i); +if (ret) {printf ("SATA link %d timeout.\n" , i);continue ; }else {
Signature · 1 line
1.8.1.2
PATCH v2 6/8 ahci: handle COMINIT received during spin-up
In reply to Rob HerringFrom: Rob Herring <[email protected]>
Some Intel SSDs can send a COMINIT after the initial COMRESET. This causes the link to go down and we need to re-initialize the link.
---
v2: Use define values for PORT_SCR
drivers/block/ahci.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/block/ahci.c +12 -0
@@ -243,8 +243,20 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent)if (!(tmp & (ATA_STAT_BUSY |ATA_STAT_DRQ )))break ;udelay (1000 ); + tmp =readl (port_mmio +PORT_SCR_STAT ); + tmp &=PORT_SCR_STAT_DET_MASK ; +if (tmp ==PORT_SCR_STAT_DET_PHYRDY ) +break ; j++; } + + tmp =readl (port_mmio +PORT_SCR_STAT ) &PORT_SCR_STAT_DET_MASK ; +if (tmp ==PORT_SCR_STAT_DET_COMINIT ) { +debug ("SATA link %d down (COMINIT received), retrying...\n" , i); + i--; +continue ; + } +printf ("Target spinup took %d ms.\n" , j);if (j ==WAIT_MS_SPINUP )debug ("timeout.\n" );
Signature · 1 line
1.8.1.2
PATCH v2 7/8 ahci: increase spin-up timeout to 20 sec
In reply to Rob HerringFrom: Rob Herring <[email protected]>
Based on Linux libata code, most drives are less than 10 sec, but some need up to 20 sec.
---
v2: rebase to v2013.10-rc1
drivers/block/ahci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/block/ahci.c +1 -1
@@ -38,7 +38,7 @@ hd_driveid_t *ataid[AHCI_MAX_PORTS];#endif /* Maximum timeouts for each event */ -#define WAIT_MS_SPINUP 10000 +#define WAIT_MS_SPINUP 20000#define WAIT_MS_DATAIO 5000#define WAIT_MS_FLUSH 5000#define WAIT_MS_LINKUP 4
Signature · 1 line
1.8.1.2
PATCH v2 8/8 ahci: convert to use libata functions and definitions
In reply to Rob HerringFrom: Rob Herring <[email protected]>
libata already has similar functions as implemented in the ahci code. Refactor the code to use the libata variants and remove the dependency on ata.h. Convert some defines to use the version from libata.h. Also, remove some unnecessary memset's of bss data.
This is a step toward hopefully merging ahci.c and dw_ahsata.c which are essentially the same driver.
---
v2: rebase to v2013.10-rc1
drivers/block/ahci.c | 80 +++++++++++++------------------------------ include/ahci.h | 23 ------------- include/configs/MPC8544DS.h | 1 + include/configs/MPC8572DS.h | 1 + include/configs/MPC8610HPCD.h | 1 + include/configs/MPC8641HPCN.h | 1 + include/configs/P2020DS.h | 1 + include/configs/coreboot.h | 1 + include/configs/highbank.h | 1 + 9 files changed, 31 insertions(+), 79 deletions(-)
drivers/block/ahci.c +24 -56
@@ -16,14 +16,14 @@#include <asm/io.h> #include <malloc.h> #include <scsi.h> -#include <ata.h> +#include <libata.h> #include <linux/ctype.h> #include <ahci.h> static int ata_io_flush (u8 port);struct ahci_probe_ent *probe_ent =NULL ; -hd_driveid_t *ataid[AHCI_MAX_PORTS ]; +u16 *ataid[AHCI_MAX_PORTS ];#define writel_with_flush (a,b) do { writel(a,b); readl(b); } while (0)
@@ -240,7 +240,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) j =0 ;while (j <WAIT_MS_SPINUP ) { tmp =readl (port_mmio +PORT_TFDATA ); -if (!(tmp & (ATA_STAT_BUSY |ATA_STAT_DRQ ))) +if (!(tmp & (ATA_BUSY |ATA_DRQ )))break ;udelay (1000 ); tmp =readl (port_mmio +PORT_SCR_STAT );
@@ -378,8 +378,6 @@ static int ahci_init_one(pci_dev_t pdev)u16 vendor;int rc; -memset ((void *)ataid,0 ,sizeof (hd_driveid_t *) *AHCI_MAX_PORTS ); - probe_ent =malloc (sizeof (struct ahci_probe_ent ));memset (probe_ent,0 ,sizeof (struct ahci_probe_ent )); probe_ent->dev = pdev;
@@ -469,7 +467,7 @@ static void ahci_set_feature(u8 port)memset (fis,0 ,sizeof (fis)); fis[0 ] =0x27 ; fis[1 ] =1 <<7 ; - fis[2 ] =ATA_CMD_SETF ; + fis[2 ] =ATA_CMD_SET_FEATURES ; fis[3 ] =SETFEATURES_XFER ; fis[12 ] =__ilog2 (probe_ent->udma_mask +1 ) +0x40 -0x01 ;
@@ -607,27 +605,6 @@ static char *ata_id_strcpy(u16 *target, u16 *src, int len)return (char *)target; } - -static void dump_ataid (hd_driveid_t *ataid) -{ -debug ("(49)ataid->capability = 0x%x\n" , ataid->capability); -debug ("(53)ataid->field_valid =0x%x\n" , ataid->field_valid); -debug ("(63)ataid->dma_mword = 0x%x\n" , ataid->dma_mword); -debug ("(64)ataid->eide_pio_modes = 0x%x\n" , ataid->eide_pio_modes); -debug ("(75)ataid->queue_depth = 0x%x\n" , ataid->queue_depth); -debug ("(80)ataid->major_rev_num = 0x%x\n" , ataid->major_rev_num); -debug ("(81)ataid->minor_rev_num = 0x%x\n" , ataid->minor_rev_num); -debug ("(82)ataid->command_set_1 = 0x%x\n" , ataid->command_set_1); -debug ("(83)ataid->command_set_2 = 0x%x\n" , ataid->command_set_2); -debug ("(84)ataid->cfsse = 0x%x\n" , ataid->cfsse); -debug ("(85)ataid->cfs_enable_1 = 0x%x\n" , ataid->cfs_enable_1); -debug ("(86)ataid->cfs_enable_2 = 0x%x\n" , ataid->cfs_enable_2); -debug ("(87)ataid->csf_default = 0x%x\n" , ataid->csf_default); -debug ("(88)ataid->dma_ultra = 0x%x\n" , ataid->dma_ultra); -debug ("(93)ataid->hw_config = 0x%x\n" , ataid->hw_config); -} - -/* * SCSI INQUIRY command operation. */
@@ -641,7 +618,7 @@ static int ata_scsiop_inquiry(ccb *pccb) 95 - 4, };u8 fis[20 ]; -u8 *tmpid; +u16 *tmpid;u8 port;/* Clean ccb data buffer */
@@ -656,15 +633,16 @@ static int ata_scsiop_inquiry(ccb *pccb)/* Construct the FIS */ fis[0 ] =0x27 ;/* Host to device FIS. */ fis[1 ] =1 <<7 ;/* Command FIS. */ - fis[2 ] =ATA_CMD_IDENT ;/* Command byte. */ + fis[2 ] =ATA_CMD_ID_ATA ;/* Command byte. */ /* Read id from sata */ port = pccb->target; -if (!(tmpid =malloc (sizeof (hd_driveid_t)))) + tmpid =malloc (ATA_ID_WORDS *2 ); +if (!tmpid)return -ENOMEM ; -if (ahci_device_data_io (port, (u8 *) &fis,sizeof (fis), tmpid, -sizeof (hd_driveid_t),0 )) { +if (ahci_device_data_io (port, (u8 *) &fis,sizeof (fis), (u8 *)tmpid, +ATA_ID_WORDS *2 ,0 )) {debug ("scsi_ahci: SCSI inquiry command failure.\n" );free (tmpid);return -EIO ;
@@ -672,13 +650,16 @@ static int ata_scsiop_inquiry(ccb *pccb)if (ataid[port])free (ataid[port]); - ataid[port] = (hd_driveid_t *) tmpid; + ataid[port] = tmpid; +ata_swap_buf_le16 (tmpid,ATA_ID_WORDS );memcpy (&pccb->pdata[8 ],"ATA " ,8 ); -ata_id_strcpy ((u16 *) &pccb->pdata[16 ], (u16 *)ataid[port]->model,16 ); -ata_id_strcpy ((u16 *) &pccb->pdata[32 ], (u16 *)ataid[port]->fw_rev,4 ); +ata_id_strcpy ((u16 *) &pccb->pdata[16 ], &tmpid[ATA_ID_PROD ],16 ); +ata_id_strcpy ((u16 *) &pccb->pdata[32 ], &tmpid[ATA_ID_FW_REV ],4 ); -dump_ataid (ataid[port]); +#ifdef DEBUG +ata_dump_id (tmpid); +#endif return 0 ; }
@@ -726,7 +707,7 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write) now_blocks =min (MAX_SATA_BLOCKS_READ_WRITE , blocks); - transfer_size =ATA_BLOCKSIZE * now_blocks; + transfer_size =ATA_SECT_SIZE * now_blocks;if (transfer_size > user_buffer_size) {printf ("scsi_ahci: Error: buffer too small.\n" );return -EIO ;
@@ -781,6 +762,7 @@ static int ata_scsiop_read_write(ccb *pccb, u8 is_write)static int ata_scsiop_read_capacity10 (ccb *pccb) {u32 cap; +u64 cap64;u32 block_size;if (!ataid[pccb->target]) {
@@ -790,18 +772,11 @@ static int ata_scsiop_read_capacity10(ccb *pccb)return -EPERM ; } - cap =le32_to_cpu (ataid[pccb->target]->lba_capacity); -if (cap ==0xfffffff ) { -unsigned short *cap48 = ataid[pccb->target]->lba48_capacity; -if (cap48[2 ] || cap48[3 ]) { - cap =0xffffffff ; - }else { - cap = (le16_to_cpu (cap48[1 ]) <<16 ) | - (le16_to_cpu (cap48[0 ])); - } - } + cap64 =ata_id_n_sectors (ataid[pccb->target]); +if (cap64 >0x100000000ULL ) + cap64 =0xffffffff ; - cap =cpu_to_be32 (cap); + cap =cpu_to_be32 (cap64);memcpy (pccb->pdata, &cap,sizeof (cap)); block_size =cpu_to_be32 ((u32 )512 );
@@ -826,12 +801,7 @@ static int ata_scsiop_read_capacity16(ccb *pccb)return -EPERM ; } - cap =le32_to_cpu (ataid[pccb->target]->lba_capacity); -if (cap ==0xfffffff ) { -memcpy (&cap, ataid[pccb->target]->lba48_capacity,sizeof (cap)); - cap =le64_to_cpu (cap); - } - + cap =ata_id_n_sectors (ataid[pccb->target]); cap =cpu_to_be64 (cap);memcpy (pccb->pdata, &cap,sizeof (cap));
@@ -918,8 +888,6 @@ int ahci_init(u32 base)int i, rc =0 ;u32 linkmap; -memset (ataid,0 ,sizeof (ataid)); - probe_ent =malloc (sizeof (struct ahci_probe_ent ));memset (probe_ent,0 ,sizeof (struct ahci_probe_ent ));
include/ahci.h +0 -23
@@ -108,29 +108,6 @@#define AHCI_MAX_PORTS 32 -/* SETFEATURES stuff */ -#define SETFEATURES_XFER 0x03 -#define XFER_UDMA_7 0x47 -#define XFER_UDMA_6 0x46 -#define XFER_UDMA_5 0x45 -#define XFER_UDMA_4 0x44 -#define XFER_UDMA_3 0x43 -#define XFER_UDMA_2 0x42 -#define XFER_UDMA_1 0x41 -#define XFER_UDMA_0 0x40 -#define XFER_MW_DMA_2 0x22 -#define XFER_MW_DMA_1 0x21 -#define XFER_MW_DMA_0 0x20 -#define XFER_SW_DMA_2 0x12 -#define XFER_SW_DMA_1 0x11 -#define XFER_SW_DMA_0 0x10 -#define XFER_PIO_4 0x0C -#define XFER_PIO_3 0x0B -#define XFER_PIO_2 0x0A -#define XFER_PIO_1 0x09 -#define XFER_PIO_0 0x08 -#define XFER_PIO_SLOW 0x00 -#define ATA_FLAG_SATA (1 << 3)#define ATA_FLAG_NO_LEGACY (1 << 4)/* no legacy mode check */ #define ATA_FLAG_MMIO (1 << 6)/* use MMIO, not PIO */
include/configs/MPC8544DS.h +1 -0
@@ -318,6 +318,7 @@ extern unsigned long get_board_sys_clk(unsigned long dummy);#define CONFIG_SCSI_AHCI #ifdef CONFIG_SCSI_AHCI +#define CONFIG_LIBATA #define CONFIG_SATA_ULI5288 #define CONFIG_SYS_SCSI_MAX_SCSI_ID 4#define CONFIG_SYS_SCSI_MAX_LUN 1
include/configs/MPC8572DS.h +1 -0
@@ -539,6 +539,7 @@#define CONFIG_SCSI_AHCI #ifdef CONFIG_SCSI_AHCI +#define CONFIG_LIBATA #define CONFIG_SATA_ULI5288 #define CONFIG_SYS_SCSI_MAX_SCSI_ID 4#define CONFIG_SYS_SCSI_MAX_LUN 1
include/configs/MPC8610HPCD.h +1 -0
@@ -326,6 +326,7 @@#define CONFIG_SCSI_AHCI #ifdef CONFIG_SCSI_AHCI +#define CONFIG_LIBATA #define CONFIG_SATA_ULI5288 #define CONFIG_SYS_SCSI_MAX_SCSI_ID 4#define CONFIG_SYS_SCSI_MAX_LUN 1
include/configs/MPC8641HPCN.h +1 -0
@@ -412,6 +412,7 @@ extern unsigned long get_board_sys_clk(unsigned long dummy);#define CONFIG_SCSI_AHCI #ifdef CONFIG_SCSI_AHCI +#define CONFIG_LIBATA #define CONFIG_SATA_ULI5288 #define CONFIG_SYS_SCSI_MAX_SCSI_ID 4#define CONFIG_SYS_SCSI_MAX_LUN 1
include/configs/P2020DS.h +1 -0
@@ -513,6 +513,7 @@#define CONFIG_SCSI_AHCI #ifdef CONFIG_SCSI_AHCI +#define CONFIG_LIBATA #define CONFIG_SATA_ULI5288 #define CONFIG_SYS_SCSI_MAX_SCSI_ID 4#define CONFIG_SYS_SCSI_MAX_LUN 1
include/configs/coreboot.h +1 -0
@@ -56,6 +56,7 @@#define CONFIG_SCSI_AHCI #ifdef CONFIG_SCSI_AHCI +#define CONFIG_LIBATA #define CONFIG_SYS_64BIT_LBA #define CONFIG_SATA_INTEL 1#define CONFIG_SCSI_DEV_LIST {PCI_VENDOR_ID_INTEL, \
include/configs/highbank.h +1 -0
@@ -39,6 +39,7 @@#define CONFIG_SYS_BOOTCOUNT_ADDR 0xfff3cf0c#define CONFIG_MISC_INIT_R +#define CONFIG_LIBATA #define CONFIG_SCSI_AHCI #define CONFIG_SCSI_AHCI_PLAT #define CONFIG_SYS_SCSI_MAX_SCSI_ID 5
Signature · 1 line
1.8.1.2
PATCH v2 1/8 ahci: use ports implemented map instead of num_ports
In reply to Rob HerringQuoted 8 lines · Rob Herring
From: Richard Gibbs <[email protected]>
The AHCI driver was incorrectly using the Capabilities register NP (number of ports) field to determine which ports to activate. This commit changes it to correctly use the
PORTS_IMPLregister as a port map.Signed-off-by Richard Gibbs <[email protected]>Reviewed-by Tom Rini <[email protected]>
Applied to u-boot/master along with the rest of the series, thanks!
Signature · 8 lines
Tom -------------- next part -------------- A non-text attachment was scrubbed... Name: not available Type: application/pgp-signature Size: 836 bytes Desc: Digital signature URL: <http://lists.denx.de/pipermail/u-boot/attachments/20130906/74c2a404/attachment.pgp>