On 2023/08/18 12:08, Michael Schmitz wrote: > Hi Damien, > > thanks for the review ... > > Am 18.08.2023 um 12:51 schrieb Damien Le Moal: >> On 2023/08/18 7:12, Michael Schmitz wrote: >>> Some users of pata_falcon on Q40 have IDE disks in default >>> IDE little endian byte order, whereas legacy disks use >>> host-native big-endian byte order as on the Atari Falcon. >>> >>> Add module parameter 'data_swab' to allow connecting drives >>> with non-native data byte order. Drives selected by the >>> data_swap bit mask will have their user data byte-swapped to >>> host byte order, i.e. 'pata_falcon.data_swab=2' will byte-swap >>> all user data on drive B, leaving data on drive A in native >>> byte order. On Q40, drives on a second IDE interface may be >>> added to the bit mask as bits 2 and 3. >>> >>> Default setting is no byte swapping, i.e. compatibility with >>> the native Falcon or Q40 operating system disk format. >>> >>> Cc: William R Sowerbutts <will@xxxxxxxxxxxxxx> >>> Cc: Finn Thain <fthain@xxxxxxxxxxxxxx> >>> Cc: Geert Uytterhoeven <geert@xxxxxxxxxxxxxx> >>> Signed-off-by: Michael Schmitz <schmitzmic@xxxxxxxxx> >>> >>> --- >>> >>> Changes since RFC v4: >>> >>> Geert Uytterhoeven: >>> - don't shift static module parameter for drive 3/4 bitmask >>> - simplify bit mask calculation to always use pdev->id >>> >>> Finn Thain: >>> - correct bit numbers for drive 3/4 >>> >>> Changes since RFC v3: >>> >>> - split off this byte swap handling into separate patch >>> >>> - add hint regarding third and fourth drive on Q40 >>> >>> Finn Thain: >>> - rename module parameter to 'data_swab' to better reflect its use >>> >>> William Sowerbutts: >>> - correct IDE drive number used in data swap conditional >>> --- >>> drivers/ata/pata_falcon.c | 26 +++++++++++++++++++++++++- >>> 1 file changed, 25 insertions(+), 1 deletion(-) >>> >>> diff --git a/drivers/ata/pata_falcon.c b/drivers/ata/pata_falcon.c >>> index 346259e3bbc8..90488f565d6f 100644 >>> --- a/drivers/ata/pata_falcon.c >>> +++ b/drivers/ata/pata_falcon.c >>> @@ -33,6 +33,16 @@ >>> #define DRV_NAME "pata_falcon" >>> #define DRV_VERSION "0.1.0" >>> >>> +static int pata_falcon_swap_mask; >>> + >>> +module_param_named(data_swab, pata_falcon_swap_mask, int, 0444); >>> +MODULE_PARM_DESC(data_swab, "Data byte swap enable/disable bitmap (0x1==drive1, 0x2==drive2, 0x4==drive3, 0x8==drive4, default==0)"); >>> + >>> +struct pata_falcon_priv { >>> + unsigned int swap_mask; >>> + bool swap_data; >>> +}; >>> + >>> static const struct scsi_host_template pata_falcon_sht = { >>> ATA_PIO_SHT(DRV_NAME), >>> }; >>> @@ -44,13 +54,15 @@ static unsigned int pata_falcon_data_xfer(struct ata_queued_cmd *qc, >>> struct ata_device *dev = qc->dev; >>> struct ata_port *ap = dev->link->ap; >>> void __iomem *data_addr = ap->ioaddr.data_addr; >>> + struct pata_falcon_priv *priv = ap->private_data; >>> unsigned int words = buflen >> 1; >>> struct scsi_cmnd *cmd = qc->scsicmd; >>> + int dev_id = dev->devno; >>> bool swap = 1; >>> >>> if (dev->class == ATA_DEV_ATA && cmd && >>> !blk_rq_is_passthrough(scsi_cmd_to_rq(cmd))) >>> - swap = 0; >>> + swap = priv->swap_data && (priv->swap_mask & BIT(dev_id)); >>> >>> /* Transfer multiple of 2 bytes */ >>> if (rw == READ) { >>> @@ -123,6 +135,7 @@ static int __init pata_falcon_init_one(struct platform_device *pdev) >>> struct resource *base_res, *ctl_res, *irq_res; >>> struct ata_host *host; >>> struct ata_port *ap; >>> + struct pata_falcon_priv *priv; >>> void __iomem *base, *ctl_base; >>> int irq = 0, io_offset = 1, reg_scale = 4; >>> >>> @@ -165,6 +178,13 @@ static int __init pata_falcon_init_one(struct platform_device *pdev) >>> ap->pio_mask = ATA_PIO4; >>> ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY; >>> >>> + priv = devm_kzalloc(&pdev->dev, >>> + sizeof(struct pata_falcon_priv), GFP_KERNEL); >>> + if (!priv) >>> + return -ENOMEM; >>> + >>> + ap->private_data = priv; >>> + >>> /* N.B. this assumes data_addr will be used for word-sized I/O only */ >>> ap->ioaddr.data_addr = (void __iomem *)base_mem_res->start; >>> >>> @@ -199,6 +219,10 @@ static int __init pata_falcon_init_one(struct platform_device *pdev) >>> ap->ioaddr.altstatus_addr = ctl_base + io_offset; >>> ap->ioaddr.ctl_addr = ctl_base + io_offset; >>> >>> + priv->swap_mask = pata_falcon_swap_mask >> (2 * pdev->id); >> >> I do not understand the shift here. It seems that it will lead to >> priv->swap_mask always being 0... > > On Q40, it is possible to have two ISA IDE adapters, and two platform > devices are defined (in arch/m68k/q40/config.c) One will have > pdev->id==0, the other will have pdev->id==1. > > In the pdev->id==0 case, there's no shift of the bit mask passed in as > module parameter, so the data transfer function will examine bits 0 and > 1. That case we've verified in testing. > In the other case, we shift down by two bits, so the data transfer > function will now examine bits 2 and 3 from the module parameter. > >> >>> + if (priv->swap_mask) >>> + priv->swap_data = 1; >> >> I do not understand why priv->swap_data is needed, given that it is set to 1 if >> priv->swap_mask != 0, the above: >> >> swap = priv->swap_data && (priv->swap_mask & BIT(dev_id)); >> >> should be equivalent to the simpler: >> >> swap = priv->swap_mask & BIT(dev_id); >> >> No ? Am I missing something ? > > I had hoped to avoid the pointer dereference and bit shift in the > default (and by far most common) case where none of the bits are set. > > Compared to the simpler version, I actually just save the bit shift, so > it's probably a pointless optimization. > > Finn had suggested to simplify this even further, and use ap->private as > bit mask directly (saving the kzalloc()). If you're OK with that, I'll > change the code accordingly. Sounds good. And given that we are talking about old IDE devices, which are *really* slow, I would not worry too much about optimizing for pointer dereference :) > > Cheers, > > Michael > > >>> + >>> irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); >>> if (irq_res && irq_res->start > 0) { >>> irq = irq_res->start; >> -- Damien Le Moal Western Digital Research