Hi,
Here comes a bumnch of fixes for the ahci code, see the individual patches for details.
cheers, Gerd
Gerd Hoffmann (5): ahci/cdrom: shared bounce buffer ahci: probe each port in its own thread ahci: ignore atapi devices which are not cdroms ahci: move device registration ahci: use malloc_tmp memory for probing ports
src/ahci.c | 94 ++++++++++++++++++++++++++++++++--------------------------- src/ahci.h | 2 + src/block.c | 14 +++++++++ src/cdrom.c | 10 ++---- src/disk.h | 2 + 5 files changed, 73 insertions(+), 49 deletions(-)
This patch creates a common bounce buffer in block.c which is shared by the cdrom and ahci drivers.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/ahci.c | 7 +++---- src/block.c | 14 ++++++++++++++ src/cdrom.c | 10 ++++------ src/disk.h | 2 ++ 4 files changed, 23 insertions(+), 10 deletions(-)
diff --git a/src/ahci.c b/src/ahci.c index 99bd0bb..9da1989 100644 --- a/src/ahci.c +++ b/src/ahci.c @@ -24,7 +24,6 @@ /**************************************************************** * these bits must run in both 16bit and 32bit modes ****************************************************************/ -u8 *ahci_buf_fl VAR16VISIBLE;
// prepare sata command fis static void sata_prep_simple(struct sata_cmd_fis *fis, u8 command) @@ -269,7 +268,7 @@ ahci_disk_readwrite(struct disk_op_s *op, int iswrite) // Use a word aligned buffer for AHCI I/O int rc; struct disk_op_s localop = *op; - u8 *alignedbuf_fl = GET_GLOBAL(ahci_buf_fl); + u8 *alignedbuf_fl = GET_GLOBAL(bounce_buf_fl); u8 *position = op->buf_fl;
localop.buf_fl = alignedbuf_fl; @@ -604,9 +603,9 @@ ahci_init_controller(struct pci_device *pci) return; }
- ahci_buf_fl = malloc_low(DISK_SECTOR_SIZE); - if (!ahci_buf_fl) { + if (bounce_buf_init() < 0) { warn_noalloc(); + free(ctrl); return; }
diff --git a/src/block.c b/src/block.c index 619db67..f7e7851 100644 --- a/src/block.c +++ b/src/block.c @@ -17,6 +17,7 @@ u8 FloppyCount VAR16VISIBLE; u8 CDCount; struct drive_s *IDMap[3][CONFIG_MAX_EXTDRIVE] VAR16VISIBLE; +u8 *bounce_buf_fl VAR16VISIBLE;
struct drive_s * getDrive(u8 exttype, u8 extdriveoffset) @@ -38,6 +39,19 @@ int getDriveId(u8 exttype, struct drive_s *drive_g) return -1; }
+int bounce_buf_init(void) +{ + if (bounce_buf_fl) + return 0; + + u8 *buf = malloc_low(CDROM_SECTOR_SIZE); + if (!buf) { + warn_noalloc(); + return -1; + } + bounce_buf_fl = buf; + return 0; +}
/**************************************************************** * Disk geometry translation diff --git a/src/cdrom.c b/src/cdrom.c index 3769dfa..6351fec 100644 --- a/src/cdrom.c +++ b/src/cdrom.c @@ -18,7 +18,6 @@ ****************************************************************/
struct drive_s *cdemu_drive_gf VAR16VISIBLE; -u8 *cdemu_buf_fl VAR16VISIBLE;
static int cdemu_read(struct disk_op_s *op) @@ -33,7 +32,7 @@ cdemu_read(struct disk_op_s *op)
int count = op->count; op->count = 0; - u8 *cdbuf_fl = GET_GLOBAL(cdemu_buf_fl); + u8 *cdbuf_fl = GET_GLOBAL(bounce_buf_fl);
if (op->lba & 3) { // Partial read of first block. @@ -111,17 +110,16 @@ cdemu_setup(void) return; if (!CDCount) return; + if (bounce_buf_init() < 0) + return;
struct drive_s *drive_g = malloc_fseg(sizeof(*drive_g)); - u8 *buf = malloc_low(CDROM_SECTOR_SIZE); - if (!drive_g || !buf) { + if (!drive_g) { warn_noalloc(); free(drive_g); - free(buf); return; } cdemu_drive_gf = drive_g; - cdemu_buf_fl = buf; memset(drive_g, 0, sizeof(*drive_g)); drive_g->type = DTYPE_CDEMU; drive_g->blksize = DISK_SECTOR_SIZE; diff --git a/src/disk.h b/src/disk.h index 10a0051..ac33518 100644 --- a/src/disk.h +++ b/src/disk.h @@ -229,6 +229,7 @@ struct drive_s {
// block.c extern u8 FloppyCount, CDCount; +extern u8 *bounce_buf_fl; struct drive_s *getDrive(u8 exttype, u8 extdriveoffset); int getDriveId(u8 exttype, struct drive_s *drive_g); void map_floppy_drive(struct drive_s *drive_g); @@ -236,6 +237,7 @@ void map_hd_drive(struct drive_s *drive_g); void map_cd_drive(struct drive_s *drive_g); int process_op(struct disk_op_s *op); int send_disk_op(struct disk_op_s *op); +int bounce_buf_init(void);
// floppy.c extern struct floppy_ext_dbt_s diskette_param_table2;
Instead if creating a single thread which probes all ports one after another kick one thread per port, so ports are probed in parallel.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/ahci.c | 41 ++++++++++++++++++++--------------------- 1 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/src/ahci.c b/src/ahci.c index 9da1989..55ada5f 100644 --- a/src/ahci.c +++ b/src/ahci.c @@ -566,28 +566,18 @@ static int ahci_port_init(struct ahci_port_s *port)
// Detect any drives attached to a given controller. static void -ahci_detect(void *data) +ahci_port_detect(void *data) { - struct ahci_ctrl_s *ctrl = data; - struct ahci_port_s *port; - u32 pnr, max; + struct ahci_port_s *port = data; int rc;
- max = ctrl->caps & 0x1f; - for (pnr = 0; pnr <= max; pnr++) { - if (!(ctrl->ports & (1 << pnr))) - continue; - dprintf(2, "AHCI/%d: probing\n", pnr); - ahci_port_reset(ctrl, pnr); - port = ahci_port_alloc(ctrl, pnr); - if (port == NULL) - continue; - rc = ahci_port_init(port); - if (rc < 0) - ahci_port_release(port); - else - ahci_port_realloc(port); - } + dprintf(2, "AHCI/%d: probing\n", port->pnr); + ahci_port_reset(port->ctrl, port->pnr); + rc = ahci_port_init(port); + if (rc < 0) + ahci_port_release(port); + else + ahci_port_realloc(port); }
// Initialize an ata controller and detect its drives. @@ -595,8 +585,9 @@ static void ahci_init_controller(struct pci_device *pci) { struct ahci_ctrl_s *ctrl = malloc_fseg(sizeof(*ctrl)); + struct ahci_port_s *port; u16 bdf = pci->bdf; - u32 val; + u32 val, pnr, max;
if (!ctrl) { warn_noalloc(); @@ -627,7 +618,15 @@ ahci_init_controller(struct pci_device *pci) dprintf(2, "AHCI: cap 0x%x, ports_impl 0x%x\n", ctrl->caps, ctrl->ports);
- run_thread(ahci_detect, ctrl); + max = ctrl->caps & 0x1f; + for (pnr = 0; pnr <= max; pnr++) { + if (!(ctrl->ports & (1 << pnr))) + continue; + port = ahci_port_alloc(ctrl, pnr); + if (port == NULL) + continue; + run_thread(ahci_port_detect, port); + } }
// Locate and init ahci controllers.
Also simplify the code a bit further down the road as we know iscd must be true ;)
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/ahci.c | 15 ++++++++------- 1 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/src/ahci.c b/src/ahci.c index 55ada5f..c1b436d 100644 --- a/src/ahci.c +++ b/src/ahci.c @@ -547,19 +547,20 @@ static int ahci_port_init(struct ahci_port_s *port) port->drive.blksize = CDROM_SECTOR_SIZE; port->drive.sectors = (u64)-1; u8 iscd = ((buffer[0] >> 8) & 0x1f) == 0x05; + if (!iscd) { + dprintf(1, "AHCI/%d: atapi device is'nt a cdrom\n", port->pnr); + return -1; + } char *desc = znprintf(MAXDESCSIZE - , "DVD/CD [AHCI/%d: %s ATAPI-%d %s]" + , "DVD/CD [AHCI/%d: %s ATAPI-%d DVD/CD]" , port->pnr , ata_extract_model(model, MAXMODEL, buffer) - , ata_extract_version(buffer) - , (iscd ? "DVD/CD" : "Device")); + , ata_extract_version(buffer)); dprintf(1, "%s\n", desc);
// fill cdidmap - if (iscd) { - int prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0); - boot_add_cd(&port->drive, desc, prio); - } + int prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0); + boot_add_cd(&port->drive, desc, prio); } return 0; }
Stick description and boot priority into the port struct, so it holds everything needed to register the device, so we can do the registration after ahci_port_init returned.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/ahci.c | 27 ++++++++++++++------------- src/ahci.h | 2 ++ 2 files changed, 16 insertions(+), 13 deletions(-)
diff --git a/src/ahci.c b/src/ahci.c index c1b436d..ecdd3cb 100644 --- a/src/ahci.c +++ b/src/ahci.c @@ -531,17 +531,13 @@ static int ahci_port_init(struct ahci_port_s *port) adjsize >>= 10; adjprefix = 'G'; } - char *desc = znprintf(MAXDESCSIZE + port->desc = znprintf(MAXDESCSIZE , "AHCI/%d: %s ATA-%d Hard-Disk (%u %ciBytes)" , port->pnr , ata_extract_model(model, MAXMODEL, buffer) , ata_extract_version(buffer) , (u32)adjsize, adjprefix); - dprintf(1, "%s\n", desc); - - // Register with bcv system. - int prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0); - boot_add_hd(&port->drive, desc, prio); + port->prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0); } else { // found cdrom (atapi) port->drive.blksize = CDROM_SECTOR_SIZE; @@ -551,16 +547,12 @@ static int ahci_port_init(struct ahci_port_s *port) dprintf(1, "AHCI/%d: atapi device is'nt a cdrom\n", port->pnr); return -1; } - char *desc = znprintf(MAXDESCSIZE + port->desc = znprintf(MAXDESCSIZE , "DVD/CD [AHCI/%d: %s ATAPI-%d DVD/CD]" , port->pnr , ata_extract_model(model, MAXMODEL, buffer) , ata_extract_version(buffer)); - dprintf(1, "%s\n", desc); - - // fill cdidmap - int prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0); - boot_add_cd(&port->drive, desc, prio); + port->prio = bootprio_find_ata_device(ctrl->pci_tmp, pnr, 0); } return 0; } @@ -577,8 +569,17 @@ ahci_port_detect(void *data) rc = ahci_port_init(port); if (rc < 0) ahci_port_release(port); - else + else { ahci_port_realloc(port); + dprintf(1, "AHCI/%d: registering: "%s"\n", port->pnr, port->desc); + if (!port->atapi) { + // Register with bcv system. + boot_add_hd(&port->drive, port->desc, port->prio); + } else { + // fill cdidmap + boot_add_cd(&port->drive, port->desc, port->prio); + } + } }
// Initialize an ata controller and detect its drives. diff --git a/src/ahci.h b/src/ahci.h index 98ade63..c3d3a70 100644 --- a/src/ahci.h +++ b/src/ahci.h @@ -75,6 +75,8 @@ struct ahci_port_s { struct ahci_cmd_s *cmd; u32 pnr; u32 atapi; + char *desc; + int prio; };
void ahci_setup(void);
Also allocate the ahci port struct itself from tmp memory for probing, then copy to fseg memory in case we detected some device. This way we don't waste fseg memory for unused ports.
Signed-off-by: Gerd Hoffmann kraxel@redhat.com --- src/ahci.c | 14 +++++++++++--- 1 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/src/ahci.c b/src/ahci.c index ecdd3cb..9b3ce2f 100644 --- a/src/ahci.c +++ b/src/ahci.c @@ -383,7 +383,7 @@ ahci_port_reset(struct ahci_ctrl_s *ctrl, u32 pnr) static struct ahci_port_s* ahci_port_alloc(struct ahci_ctrl_s *ctrl, u32 pnr) { - struct ahci_port_s *port = malloc_fseg(sizeof(*port)); + struct ahci_port_s *port = malloc_tmp(sizeof(*port));
if (!port) { warn_noalloc(); @@ -407,10 +407,16 @@ ahci_port_alloc(struct ahci_ctrl_s *ctrl, u32 pnr) return port; }
-static void ahci_port_realloc(struct ahci_port_s *port) +static struct ahci_port_s* ahci_port_realloc(struct ahci_port_s *port) { + struct ahci_port_s *tmp; u32 cmd;
+ tmp = malloc_fseg(sizeof(*port)); + *tmp = *port; + free(port); + port = tmp; + ahci_port_reset(port->ctrl, port->pnr);
free(port->list); @@ -426,6 +432,8 @@ static void ahci_port_realloc(struct ahci_port_s *port) cmd = ahci_port_readl(port->ctrl, port->pnr, PORT_CMD); cmd |= (PORT_CMD_FIS_RX|PORT_CMD_START); ahci_port_writel(port->ctrl, port->pnr, PORT_CMD, cmd); + + return port; }
static void ahci_port_release(struct ahci_port_s *port) @@ -570,7 +578,7 @@ ahci_port_detect(void *data) if (rc < 0) ahci_port_release(port); else { - ahci_port_realloc(port); + port = ahci_port_realloc(port); dprintf(1, "AHCI/%d: registering: "%s"\n", port->pnr, port->desc); if (!port->atapi) { // Register with bcv system.
On Thu, Aug 04, 2011 at 07:36:26PM +0200, Gerd Hoffmann wrote:
Hi,
Here comes a bumnch of fixes for the ahci code, see the individual patches for details.
Thanks! I've applied these and the Kconfig change.
-Kevin