Linux block layer
 help / color / mirror / Atom feed
* [PATCH v2 00/32] block/swim: Fixes and improvements
@ 2026-08-17  1:17 Finn Thain
  2026-08-17  1:17 ` [PATCH v2 26/32] swim: Move swd initialization Finn Thain
                   ` (31 more replies)
  0 siblings, 32 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Joshua Thompson, Geert Uytterhoeven, linux-block, linux-kernel,
	linux-m68k, Omar Sandoval

I recently had a need for the 'swim' driver but found that it was too buggy
to be useful for my purposes. I had two aims in mind--

Firstly, I needed this driver to help me test my new BMoW Floppy Emu for 
emulation correctness. Being that Linux is open source and MacOS is not,
this driver should be ideal for that.

Secondly, I needed to realign the heads in some disk drives. The swim driver
has most of the code needed for a feedback loop for manual re-alignment, so
I wrote the remaining code and pushed it to a repo here:
https://github.com/fthain/linux/commits/swim/

These patches fix all the bugs I found. They improve stability,
compatibility and performance. Additional patches improve source code
quality by removing redundant code and cleaning up a bit.

This patch series was successfully tested on the following systems.

Mac Quadra 650 - SWIM 2 with Mitsubishi FDD
Mac LC III     - SWIM 2 with Mitsubishi FDD and Sony FDD
Mac Quadra 700 - SWIM with Sony FDD
Mac IIvx       - SWIM with Sony FDD

---
Changed since v1:
 - Patches 1/31, 19/31, 23/31 were revised as per Laurent's remarks.
 - Some minor improvements to patches 9/31, 13/31 and 16/31.
 - Added patch 24/32 to fix a bug causing silent IO corruption instead
   of an IO error.

---

Finn Thain (32):
  swim: Assert strobe with stable outputs
  swim: Select appropriate drive once only
  swim: Enable the drive when probing
  swim: Don't disable drive after every sector
  swim: Perform ISM/IWM mode switching according to specs
  swim: Configure parameter memory
  swim: Enable clock divider only where appropriate
  swim: Don't start motor until medium is present
  swim: Recalibrate when drive is probed
  swim: Add track zero recalibration delay
  swim: Handle FIFO timeout error
  swim: Simplify return value initialization
  swim: Check for CRC errors
  swim: Check error register during sector read
  swim: Don't use the mark register to read data
  swim: Fix buffer overflow
  swim: Convert to blocking queue
  swim: Remove redundant RELAX actions
  swim: Deduplicate polling loops
  swim: Check drive ready bit
  swim: Revisit delays
  swim: Remove pointless mode0 register write
  swim: Don't needlessly re-read sectors
  swim: Don't search beyond the first data mark
  swim: Remove pointless specifiers
  swim: Move swd initialization
  swim: Add some helpful references
  swim: Remove unused macro definitions
  swim: Clean up whitespace
  swim: Define macros for constants
  swim: Define symbols for constants
  swim: Unexport global symbols

 arch/m68k/mac/config.c   |  31 ++-
 drivers/block/swim.c     | 447 ++++++++++++++++++++-------------------
 drivers/block/swim_asm.S | 358 ++++++++++++++++---------------
 3 files changed, 449 insertions(+), 387 deletions(-)

-- 
2.52.0


^ permalink raw reply	[flat|nested] 33+ messages in thread

* [PATCH v2 01/32] swim: Assert strobe with stable outputs
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
  2026-08-17  1:17 ` [PATCH v2 26/32] swim: Move swd initialization Finn Thain
  2026-08-17  1:17 ` [PATCH v2 23/32] swim: Don't needlessly re-read sectors Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 31/32] swim: Define symbols for constants Finn Thain
                   ` (28 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

Inside Macintosh says, "Be sure that you don't change CA0-CA2 or SEL
while LSTRB is high". Unfortunately, those bits do change. The CA0-CA2
outputs become inputs when (LSTRB << 4) | LSTRB gets written to the
phase register. Then LSTRB is driven low (with CA0-CA2 bits set).

This is a problem because the drive interprets a STEP command as an
EJECT command when these pins float high. This occurs intermittently,
perhaps because interrupts are disabled and the race condition happens
to end well. However, when I add code to step the heads with interrupts
enabled, the disk always ejects.

Keep the four phase pin directions set to output and hold their levels
constant during LSTRB signalling. Introduce the PHASE_PIN_DIRECTION
macro to separate the pin configuration from the logic level changes.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
Changed since v1:
 - Added the PHASE_PIN_DIRECTION macro to improve readability.
 - Re-arranged macro definition groups so as to agree with their
 descriptions.
---
 drivers/block/swim.c | 62 ++++++++++++++++++++++----------------------
 1 file changed, 31 insertions(+), 31 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 0ccc12a72388..5d89e7813049 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -87,37 +87,37 @@ struct iwm {
 #define iwm_write(base, reg, v) 	out_8(&(base)->reg, (v))
 #define iwm_read(base, reg)		in_8(&(base)->reg)
 
-/* bits in phase register */
+/* Bits in phase register */
 
-#define SEEK_POSITIVE	0x070
-#define SEEK_NEGATIVE	0x074
-#define STEP		0x071
-#define MOTOR_ON	0x072
-#define MOTOR_OFF	0x076
-#define INDEX		0x073
-#define EJECT		0x077
-#define SETMFM		0x171
-#define SETGCR		0x175
-
-#define RELAX		0x033
-#define LSTRB		0x008
-
-#define CA_MASK		0x077
+#define RELAX		0x03
+#define LSTRB		0x08
+#define CA_MASK		0x07
+#define PHASE_PIN_DIR	0xF0
 
 /* Select values for swim_select and swim_readbit */
 
-#define READ_DATA_0	0x074
-#define ONEMEG_DRIVE	0x075
-#define SINGLE_SIDED	0x076
-#define DRIVE_PRESENT	0x077
-#define DISK_IN		0x170
-#define WRITE_PROT	0x171
-#define TRACK_ZERO	0x172
-#define TACHO		0x173
-#define READ_DATA_1	0x174
-#define GCR_MODE	0x175
-#define SEEK_COMPLETE	0x176
-#define TWOMEG_MEDIA	0x177
+#define SEEK_POSITIVE	0x000
+#define SEEK_NEGATIVE	0x004
+#define STEP		0x001
+#define MOTOR_ON	0x002
+#define MOTOR_OFF	0x006
+#define INDEX		0x003
+#define EJECT		0x007
+#define SETMFM		0x101
+#define SETGCR		0x105
+
+#define READ_DATA_0	0x004
+#define ONEMEG_DRIVE	0x005
+#define SINGLE_SIDED	0x006
+#define DRIVE_PRESENT	0x007
+#define DISK_IN		0x100
+#define WRITE_PROT	0x101
+#define TRACK_ZERO	0x102
+#define TACHO		0x103
+#define READ_DATA_1	0x104
+#define GCR_MODE	0x105
+#define SEEK_COMPLETE	0x106
+#define TWOMEG_MEDIA	0x107
 
 /* Bits in handshake register */
 
@@ -269,11 +269,11 @@ static inline int get_swim_mode(struct swim __iomem *base)
 
 static inline void swim_select(struct swim __iomem *base, int sel)
 {
-	swim_write(base, phase, RELAX);
+	swim_write(base, phase, RELAX | PHASE_PIN_DIR);
 
 	via1_set_head(sel & 0x100);
 
-	swim_write(base, phase, sel & CA_MASK);
+	swim_write(base, phase, (sel & CA_MASK) | PHASE_PIN_DIR);
 }
 
 static inline void swim_action(struct swim __iomem *base, int action)
@@ -284,9 +284,9 @@ static inline void swim_action(struct swim __iomem *base, int action)
 
 	swim_select(base, action);
 	udelay(1);
-	swim_write(base, phase, (LSTRB<<4) | LSTRB);
+	swim_write(base, phase, LSTRB | action | PHASE_PIN_DIR);
 	udelay(1);
-	swim_write(base, phase, (LSTRB<<4) | ((~LSTRB) & 0x0F));
+	swim_write(base, phase, action | PHASE_PIN_DIR);
 	udelay(1);
 
 	local_irq_restore(flags);
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 02/32] swim: Select appropriate drive once only
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (17 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 08/32] swim: Don't start motor until medium is present Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 15/32] swim: Don't use the mark register to read data Finn Thain
                   ` (12 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

Before turning off the spindle motor, call swim_drive() to select the
appropriate drive. Remove the swim_drive() call from swim_add_floppy()
because it was already called by swim_floppy_init().

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 5d89e7813049..4721e073a874 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -679,8 +679,10 @@ static void floppy_release(struct gendisk *disk)
 	else if (fs->ref_count > 0)
 		--fs->ref_count;
 
-	if (fs->ref_count == 0)
+	if (fs->ref_count == 0) {
+		swim_drive(base, fs->location);
 		swim_motor(base, OFF);
+	}
 	mutex_unlock(&swim_mutex);
 }
 
@@ -752,8 +754,6 @@ static int swim_add_floppy(struct swim_priv *swd, enum drive_location location)
 
 	fs->location = location;
 
-	swim_drive(base, location);
-
 	swim_motor(base, OFF);
 
 	fs->type = HD_MEDIA;
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 03/32] swim: Enable the drive when probing
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (13 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 24/32] swim: Don't search beyond the first data mark Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 13/32] swim: Check for CRC errors Finn Thain
                   ` (16 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

According to the ISM spec, the MOTON bit "causes the Enable 1 and Enable 2
signals to be turned on to the drive." It doesn't actually turn on the
motor. When selecting a drive, enable MOTON. Disable it upon eject or
release. This fixes detection of the Sony FDHD drive.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 4721e073a874..4ddb87977fe1 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -154,8 +154,9 @@ struct iwm {
 /*----------------------------------------------------------------------------*/
 
 enum drive_location {
-	INTERNAL_DRIVE = 0x02,
-	EXTERNAL_DRIVE = 0x04,
+	NO_DRIVE = 0,
+	INTERNAL_DRIVE = BIT(1),
+	EXTERNAL_DRIVE = BIT(2),
 };
 
 enum media_type {
@@ -311,9 +312,15 @@ static inline void swim_drive(struct swim __iomem *base,
 	if (location == INTERNAL_DRIVE) {
 		swim_write(base, mode0, EXTERNAL_DRIVE); /* clear drive 1 bit */
 		swim_write(base, mode1, INTERNAL_DRIVE); /* set drive 0 bit */
+		swim_write(base, mode1, MOTON);
 	} else if (location == EXTERNAL_DRIVE) {
 		swim_write(base, mode0, INTERNAL_DRIVE); /* clear drive 0 bit */
 		swim_write(base, mode1, EXTERNAL_DRIVE); /* set drive 1 bit */
+		swim_write(base, mode1, MOTON);
+	} else {
+		swim_write(base, mode0, INTERNAL_DRIVE);
+		swim_write(base, mode0, EXTERNAL_DRIVE);
+		swim_write(base, mode0, MOTON);
 	}
 }
 
@@ -447,6 +454,7 @@ static int floppy_eject(struct floppy_state *fs)
 	swim_drive(base, fs->location);
 	swim_motor(base, OFF);
 	swim_eject(base);
+	swim_drive(base, NO_DRIVE);
 
 	fs->disk_in = 0;
 	fs->ejected = 1;
@@ -652,8 +660,10 @@ static int floppy_open(struct gendisk *disk, blk_mode_t mode)
 	else if (fs->ref_count > 0)
 		--fs->ref_count;
 
-	if (fs->ref_count == 0)
+	if (fs->ref_count == 0) {
 		swim_motor(base, OFF);
+		swim_drive(base, NO_DRIVE);
+	}
 	return err;
 }
 
@@ -682,6 +692,7 @@ static void floppy_release(struct gendisk *disk)
 	if (fs->ref_count == 0) {
 		swim_drive(base, fs->location);
 		swim_motor(base, OFF);
+		swim_drive(base, NO_DRIVE);
 	}
 	mutex_unlock(&swim_mutex);
 }
@@ -804,6 +815,7 @@ static int swim_floppy_init(struct swim_priv *swd)
 	if (swim_readbit(base, DRIVE_PRESENT) &&
 	    !swim_readbit(base, ONEMEG_DRIVE))
 		swim_add_floppy(swd, EXTERNAL_DRIVE);
+	swim_drive(base, NO_DRIVE);
 
 	/* register floppy drives */
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 04/32] swim: Don't disable drive after every sector
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (8 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 19/32] swim: Deduplicate polling loops Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 11/32] swim: Handle FIFO timeout error Finn Thain
                   ` (21 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

This fixes multi-sector reads on a Sony drive. The Mitsubishi drive
doesn't seem to care either way.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 4ddb87977fe1..3f92677ad127 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -473,8 +473,6 @@ static inline int swim_read_sector(struct floppy_state *fs,
 	short i;
 
 	swim_track(fs, track);
-
-	swim_write(base, mode1, MOTON);
 	swim_head(base, side);
 	swim_write(base, mode0, side);
 
@@ -490,8 +488,6 @@ static inline int swim_read_sector(struct floppy_state *fs,
 	}
 	local_irq_restore(flags);
 
-	swim_write(base, mode0, MOTON);
-
 	if ((header.side != side)  || (header.track != track) ||
 	     (header.sector != sector))
 		return 0;
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 05/32] swim: Perform ISM/IWM mode switching according to specs
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (21 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 30/32] swim: Define macros for constants Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 18/32] swim: Remove redundant RELAX actions Finn Thain
                   ` (8 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

The SWIM spec says, "MOTOREN must be low to switch modes" and "after
switching from ISM to IWM, the very first command must be a clear L7".

The ISM spec says, MOTOREN "must not be cleared until after the Action
bit is cleared". Perform those operations in the correct sequence.

When switching to ISM mode, the Mode register has to be selected with a
particular sequence of bit flips. Set q7 low then q6 low then mtrOff.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 3f92677ad127..190b2e1b5b0e 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -149,6 +149,7 @@ struct iwm {
 #define ACTION		0x08
 #define WRITE_MODE	0x10
 #define HEDSEL		0x20
+#define ISM_SELECT	0x40
 #define MOTON		0x80
 
 /*----------------------------------------------------------------------------*/
@@ -223,18 +224,21 @@ extern int swim_read_sector_data(struct swim __iomem *base,
 static DEFINE_MUTEX(swim_mutex);
 static inline void set_swim_mode(struct swim __iomem *base, int enable)
 {
-	struct iwm __iomem *iwm_base;
+	struct iwm __iomem *iwm_base = (struct iwm __iomem *)base;
 	unsigned long flags;
 
 	if (!enable) {
-		swim_write(base, mode0, 0xf8);
+		swim_write(base, mode0, ACTION);
+		swim_write(base, mode0, ENBL1 | ENBL2 | MOTON);
+		swim_write(base, mode0, ISM_SELECT);
+		iwm_read(iwm_base, q7L);
 		return;
 	}
 
-	iwm_base = (struct iwm __iomem *)base;
 	local_irq_save(flags);
 
 	iwm_read(iwm_base, q7L);
+	iwm_read(iwm_base, q6L);
 	iwm_read(iwm_base, mtrOff);
 	iwm_read(iwm_base, q6H);
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 06/32] swim: Configure parameter memory
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (28 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 17/32] swim: Convert to blocking queue Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 09/32] swim: Recalibrate when drive is probed Finn Thain
  2026-08-17  1:17 ` [PATCH v2 07/32] swim: Enable clock divider only where appropriate Finn Thain
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

The original SWIM chip has a 16 byte memory to store parameters which
control read/write timing. The SWIM 2 chip retains the last 4 parameters
which control write pre-compensation, but omits the first 12. Hence
SWIM 2 can perform reads without any parameter memory setup but SWIM 1
cannot.

Configure the SWIM parameter memory with the appropriate values so that
SWIM 1 can read too. The parameters used here were observed in SWIM chip
memory, using Macsbug, while MacOS was reading from an MFM floppy disk.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 190b2e1b5b0e..c2d7ad3f065c 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -796,6 +796,17 @@ static void swim_cleanup_floppy_disk(struct floppy_state *fs)
 	blk_mq_free_tag_set(&fs->tag_set);
 }
 
+static void swim_set_parameters(struct swim __iomem *base)
+{
+	unsigned int i;
+	static const u8 mem[] = { 0x18, 0x41, 0x2e, 0x2e, 0x18, 0x18, 0x1b, 0x1b,
+				  0x2f, 0x2f, 0x19, 0x19, 0x97, 0x1b, 0x57, 0x3b, };
+
+	swim_write(base, mode0, 0); /* reset parameter memory index */
+	for (i = 0; i < 16; ++i)
+		swim_write(base, parameter, mem[i]);
+}
+
 static int swim_floppy_init(struct swim_priv *swd)
 {
 	struct queue_limits lim = {
@@ -805,6 +816,8 @@ static int swim_floppy_init(struct swim_priv *swd)
 	int drive;
 	struct swim __iomem *base = swd->base;
 
+	swim_set_parameters(base);
+
 	/* scan floppy drives */
 
 	swim_drive(base, INTERNAL_DRIVE);
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 07/32] swim: Enable clock divider only where appropriate
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (30 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 09/32] swim: Recalibrate when drive is probed Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

Some models have a 16 MHz FCLK oscillator and others 32 MHz. Put this
information into the swim device platform_data so that the driver can
correctly enable the clock divider. When this is enabled incorrectly,
nothing can be read and failures from the Error Correction Machine are
flagged in the error register.

This is chip initialization, so do this in swim_floppy_init() rather
than floppy_open(). Drop the udelay() which was apparently copied and
pasted from swim3.c, where it relates to interrupts (of which this chip
has none).

Cc: Joshua Thompson <funaho@jurai.org>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 arch/m68k/mac/config.c | 31 ++++++++++++++++++++++++++++++-
 drivers/block/swim.c   | 11 +++++++----
 2 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index c0033f885ed4..dba3de21c3c4 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -984,8 +984,37 @@ static int __init mac_platform_init(void)
 			.start = swim_base,
 			.end   = swim_base + 0x1FFF,
 		};
+		unsigned int data = 0;
+
+		/* Models in this list are supposed to run FCLK at 32 MHz */
+		switch (macintosh_config->ident) {
+		case MAC_MODEL_CCL:
+		case MAC_MODEL_CCLII:
+		case MAC_MODEL_LCIII:
+		case MAC_MODEL_Q605:
+		case MAC_MODEL_Q605_ACC:
+		case MAC_MODEL_Q610:
+		case MAC_MODEL_Q630:
+		case MAC_MODEL_Q650:
+		case MAC_MODEL_Q800:
+		case MAC_MODEL_P460:
+		case MAC_MODEL_P475:
+		case MAC_MODEL_P475F:
+		case MAC_MODEL_P520:
+		case MAC_MODEL_P550:
+		case MAC_MODEL_P575:
+		case MAC_MODEL_P588:
+		case MAC_MODEL_TV:
+		case MAC_MODEL_C610:
+		case MAC_MODEL_C650:
+		case MAC_MODEL_PB190:
+		case MAC_MODEL_PB520:
+			data = 1;
+			break;
+		}
 
-		platform_device_register_simple("swim", -1, &swim_rsrc, 1);
+		platform_device_register_resndata(NULL, "swim", -1, &swim_rsrc, 1,
+						  &data, sizeof(data));
 	}
 
 	/*
diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index c2d7ad3f065c..597d35b514ae 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -628,8 +628,7 @@ static int floppy_open(struct gendisk *disk, blk_mode_t mode)
 		fs->ref_count = -1;
 	else
 		fs->ref_count++;
-	swim_write(base, setup, S_IBM_DRIVE  | S_FCLK_DIV2);
-	udelay(10);
+
 	swim_drive(base, fs->location);
 	swim_motor(base, ON);
 	swim_action(base, SETMFM);
@@ -807,8 +806,10 @@ static void swim_set_parameters(struct swim __iomem *base)
 		swim_write(base, parameter, mem[i]);
 }
 
-static int swim_floppy_init(struct swim_priv *swd)
+static int swim_floppy_init(struct platform_device *pdev)
 {
+	struct swim_priv *swd = platform_get_drvdata(pdev);
+	unsigned int *data = pdev->dev.platform_data;
 	struct queue_limits lim = {
 		.features		= BLK_FEAT_ROTATIONAL,
 	};
@@ -816,6 +817,8 @@ static int swim_floppy_init(struct swim_priv *swd)
 	int drive;
 	struct swim __iomem *base = swd->base;
 
+	swim_write(base, setup, S_IBM_DRIVE | (*data ? S_FCLK_DIV2 : 0));
+
 	swim_set_parameters(base);
 
 	/* scan floppy drives */
@@ -930,7 +933,7 @@ static int swim_probe(struct platform_device *dev)
 
 	swd->base = swim_base;
 
-	ret = swim_floppy_init(swd);
+	ret = swim_floppy_init(dev);
 	if (ret)
 		goto out_kfree;
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 08/32] swim: Don't start motor until medium is present
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (16 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 25/32] swim: Remove pointless specifiers Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 02/32] swim: Select appropriate drive once only Finn Thain
                   ` (13 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

The spindle motor should not be running when a disk is to be inserted.
Don't start the motor while the drive is empty.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 597d35b514ae..6a49fc51f5d2 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -630,8 +630,7 @@ static int floppy_open(struct gendisk *disk, blk_mode_t mode)
 		fs->ref_count++;
 
 	swim_drive(base, fs->location);
-	swim_motor(base, ON);
-	swim_action(base, SETMFM);
+
 	if (fs->ejected)
 		setup_medium(fs);
 	if (!fs->disk_in) {
@@ -639,6 +638,9 @@ static int floppy_open(struct gendisk *disk, blk_mode_t mode)
 		goto out;
 	}
 
+	swim_motor(base, ON);
+	swim_action(base, SETMFM);
+
 	set_capacity(fs->disk, fs->total_secs);
 
 	if (mode & BLK_OPEN_NDELAY)
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 09/32] swim: Recalibrate when drive is probed
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (29 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 06/32] swim: Configure parameter memory Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 07/32] swim: Enable clock divider only where appropriate Finn Thain
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

Track zero recalibration can be slow and is normally done only once i.e.
during system POST or boot-up. Recalibrate once after the drive is probed
rather than every time the device is opened. Don't register the drive if
recalibration fails. Park the heads before ejecting.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
Changed since v1:
 - Refactor swim_add_floppy() slightly. Start spindle motor before
   recalibration if a disk is loaded.
 - Change return type of swim_add_floppy() to void.
 - Park heads at track 40 because that's what MacOS does.
---
 drivers/block/swim.c | 37 +++++++++++++++++--------------------
 1 file changed, 17 insertions(+), 20 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 6a49fc51f5d2..9abf93bc0980 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -412,6 +412,7 @@ static inline int swim_track00(struct swim __iomem *base)
 	if (swim_readbit(base, TRACK_ZERO))
 		return 0;
 
+	pr_err("swim: track zero recalibration failed\n");
 	return -1;
 }
 
@@ -456,6 +457,7 @@ static int floppy_eject(struct floppy_state *fs)
 	struct swim __iomem *base = fs->swd->base;
 
 	swim_drive(base, fs->location);
+	swim_track(fs, 40);
 	swim_motor(base, OFF);
 	swim_eject(base);
 	swim_drive(base, NO_DRIVE);
@@ -596,13 +598,6 @@ static void setup_medium(struct floppy_state *fs)
 		struct floppy_struct *g;
 		fs->disk_in = 1;
 		fs->write_protected = swim_readbit(base, WRITE_PROT);
-
-		if (swim_track00(base))
-			printk(KERN_ERR
-				"SWIM: cannot move floppy head to track 0\n");
-
-		swim_track00(base);
-
 		fs->type = swim_readbit(base, TWOMEG_MEDIA) ?
 			HD_MEDIA : DD_MEDIA;
 		fs->head_number = swim_readbit(base, SINGLE_SIDED) ? 1 : 2;
@@ -610,7 +605,6 @@ static void setup_medium(struct floppy_state *fs)
 		fs->total_secs = g->size;
 		fs->secpercyl = g->head * g->sect;
 		fs->secpertrack = g->sect;
-		fs->track = 0;
 	} else {
 		fs->disk_in = 0;
 	}
@@ -759,24 +753,33 @@ static const struct block_device_operations floppy_fops = {
 	.check_events	 = floppy_check_events,
 };
 
-static int swim_add_floppy(struct swim_priv *swd, enum drive_location location)
+static void swim_add_floppy(struct swim_priv *swd, enum drive_location location)
 {
 	struct floppy_state *fs = &swd->unit[swd->floppy_count];
 	struct swim __iomem *base = swd->base;
 
-	fs->location = location;
+	swim_drive(base, location);
+	if (!swim_readbit(base, DRIVE_PRESENT) ||
+	    swim_readbit(base, ONEMEG_DRIVE))
+		goto out;
+	if (swim_readbit(base, DISK_IN))
+		swim_motor(base, ON);
+	if (swim_track00(base))
+		goto out;
 
-	swim_motor(base, OFF);
+	fs->location = location;
 
 	fs->type = HD_MEDIA;
 	fs->head_number = 2;
 
 	fs->ref_count = 0;
 	fs->ejected = 1;
+	fs->track = 0;
 
 	swd->floppy_count++;
 
-	return 0;
+out:
+	swim_motor(base, OFF);
 }
 
 static const struct blk_mq_ops swim_mq_ops = {
@@ -825,14 +828,8 @@ static int swim_floppy_init(struct platform_device *pdev)
 
 	/* scan floppy drives */
 
-	swim_drive(base, INTERNAL_DRIVE);
-	if (swim_readbit(base, DRIVE_PRESENT) &&
-	    !swim_readbit(base, ONEMEG_DRIVE))
-		swim_add_floppy(swd, INTERNAL_DRIVE);
-	swim_drive(base, EXTERNAL_DRIVE);
-	if (swim_readbit(base, DRIVE_PRESENT) &&
-	    !swim_readbit(base, ONEMEG_DRIVE))
-		swim_add_floppy(swd, EXTERNAL_DRIVE);
+	swim_add_floppy(swd, INTERNAL_DRIVE);
+	swim_add_floppy(swd, EXTERNAL_DRIVE);
 	swim_drive(base, NO_DRIVE);
 
 	/* register floppy drives */
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 10/32] swim: Add track zero recalibration delay
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (26 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 21/32] swim: Revisit delays Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 17/32] swim: Convert to blocking queue Finn Thain
                   ` (3 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

The UPD72070 spec indicates that the track zero sensor can take 3 ms
to stabilize following a STEP command so add a call to msleep().
Remove the duplicate swim_readbit() call as there's no need for that
once the sensor signal has stabilized.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 9abf93bc0980..c9cd0748c878 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -402,16 +402,15 @@ static inline int swim_track00(struct swim __iomem *base)
 	for (try = 0; try < 100; try++) {
 
 		swim_select(base, RELAX);
+		msleep(3);
+
 		if (swim_readbit(base, TRACK_ZERO))
-			break;
+			return 0;
 
 		if (swim_step(base))
-			return -1;
+			break;
 	}
 
-	if (swim_readbit(base, TRACK_ZERO))
-		return 0;
-
 	pr_err("swim: track zero recalibration failed\n");
 	return -1;
 }
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 11/32] swim: Handle FIFO timeout error
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (9 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 04/32] swim: Don't disable drive after every sector Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 28/32] swim: Remove unused macro definitions Finn Thain
                   ` (20 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

When polling the FIFO for a mark byte in the sector header, don't
return zero if the timeout counter has expired, return an error code.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim_asm.S | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/block/swim_asm.S b/drivers/block/swim_asm.S
index 3d7a2d87595a..208622ac4aeb 100644
--- a/drivers/block/swim_asm.S
+++ b/drivers/block/swim_asm.S
@@ -79,7 +79,7 @@ wait_addr_mark_byte:
 
 	tstb	%a2@
 	dbmi	%d2, wait_addr_mark_byte
-	bpl	header_exit
+	bpl	signal_nonyb
 
 	moveb	%a3@, %d3
 	cmpb	%a0@+, %d3
@@ -136,7 +136,6 @@ crc1:	tstb	%a2@
 
 	tstb	%a3@(read_error - read_mark)
 
-header_exit:
 	moveq	#0, %d0
 	moveb	#0x18, %a3@(write_mode0 - read_mark)
 	rts
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 12/32] swim: Simplify return value initialization
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (3 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 31/32] swim: Define symbols for constants Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 20/32] swim: Check drive ready bit Finn Thain
                   ` (26 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

Initialize the error result once only. Update the result only after a
successful read.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim_asm.S | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/block/swim_asm.S b/drivers/block/swim_asm.S
index 208622ac4aeb..31fc63b074dc 100644
--- a/drivers/block/swim_asm.S
+++ b/drivers/block/swim_asm.S
@@ -47,6 +47,7 @@ swim_read_sector_header:
 	link	%a6, #0
 	moveml	%d1-%d5/%a0-%a4,%sp@-
 	movel	%a6@(0x0c), %a4
+	moveq	#-1, %d0
 	bsr	mfm_read_addrmark
 	moveml	%sp@+, %d1-%d5/%a0-%a4
 	unlk	%a6
@@ -61,7 +62,6 @@ mfm_read_addrmark:
 	movel	%a6@(0x08), %a3
 	lea	%a3@(read_handshake), %a2
 	lea	%a3@(read_mark), %a3
-	moveq	#-1, %d0
 	movew	#seek_time, %d2
 
 wait_header_init:
@@ -137,10 +137,7 @@ crc1:	tstb	%a2@
 	tstb	%a3@(read_error - read_mark)
 
 	moveq	#0, %d0
-	moveb	#0x18, %a3@(write_mode0 - read_mark)
-	rts
 signal_nonyb:
-	moveq	#-1, %d0
 	moveb	#0x18, %a3@(write_mode0 - read_mark)
 	rts
 
@@ -149,6 +146,7 @@ swim_read_sector_data:
 	link	%a6, #0
 	moveml	%d1-%d5/%a0-%a5,%sp@-
 	movel	%a6@(0x0c), %a4
+	moveq	#-1, %d0
 	bsr	mfm_read_data
 	moveml	%sp@+, %d1-%d5/%a0-%a5
 	unlk	%a6
@@ -228,15 +226,12 @@ data_crc1:
 
 	tstb	%a3@(read_error - read_mark)
 
-	moveb	#0x18, %a3@(write_mode0 - read_mark)
-
 	/* return number of bytes read */
 
 	movel	#sector_size, %d0
 	addw	#1, %d4
 	subl	%d4, %d0
-	rts
+
 data_exit:
 	moveb	#0x18, %a3@(write_mode0 - read_mark)
-	moveq	#-1, %d0
 	rts
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 13/32] swim: Check for CRC errors
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (14 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 03/32] swim: Enable the drive when probing Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 25/32] swim: Remove pointless specifiers Finn Thain
                   ` (15 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

After reading either the sector header or sector data, examine that flag
in the handshake register which holds the result of the CRC calculation.
CRC validation has to take place with the last byte still in the FIFO.
This flag can't be checked by the caller because by then all bytes will
have been retrieved from the FIFO. Return an error code when appropriate.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
Changed since v1:
 - Load handshake register a second time because that's what MacOS does.
---
 drivers/block/swim_asm.S | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/block/swim_asm.S b/drivers/block/swim_asm.S
index 31fc63b074dc..533e3bf02fa9 100644
--- a/drivers/block/swim_asm.S
+++ b/drivers/block/swim_asm.S
@@ -42,6 +42,8 @@
 	.equ	max_retry, 40
 	.equ	sector_size, 512
 
+	.equ	.Lhr_crc_error,		0x02
+
 	.global swim_read_sector_header
 swim_read_sector_header:
 	link	%a6, #0
@@ -128,12 +130,16 @@ crc0:	tstb	%a2@
 
 	moveq	#max_retry, %d2
 
-crc1:	tstb	%a2@
+crc1:	moveb	%a2@, %d5
 	dbmi	%d2, crc1
 	bpl	signal_nonyb
 
 	moveb	%a3@, %a4@(o_crc1)
 
+	moveb	%a2@, %d5
+	andb	#.Lhr_crc_error, %d5
+	bne	signal_nonyb
+
 	tstb	%a3@(read_error - read_mark)
 
 	moveq	#0, %d0
@@ -212,17 +218,21 @@ data_crc0:
 	dbmi	%d2, data_crc0
 	bpl	data_exit
 
-	moveb	%a3@, %d5
+	moveb	%a3@, %d2
 
 	moveq	#max_retry, %d2
 
 data_crc1:
 
-	tstb	%a2@
+	moveb	%a2@, %d5
 	dbmi	%d2, data_crc1
 	bpl	data_exit
 
-	moveb	%a3@, %d5
+	moveb	%a3@, %d2
+
+	moveb	%a2@, %d5
+	andb	#.Lhr_crc_error, %d5
+	bne	data_exit
 
 	tstb	%a3@(read_error - read_mark)
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 14/32] swim: Check error register during sector read
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (24 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 29/32] swim: Clean up whitespace Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 21/32] swim: Revisit delays Finn Thain
                   ` (5 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

Clear the error register only once before a sector read operation. Don't
clear it afterwards -- the caller needs it. Check the error register in
swim_read_sector() and return the appropriate error when necessary. Fully
validate the sector header. Don't terminate the search loop early just
because an erroneous sector header showed up.

Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c     | 13 +++++++------
 drivers/block/swim_asm.S |  8 --------
 2 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index c9cd0748c878..33374498d621 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -483,20 +483,21 @@ static inline int swim_read_sector(struct floppy_state *fs,
 
 	local_irq_save(flags);
 	for (i = 0; i < 36; i++) {
-		ret = swim_read_sector_header(base, &header);
-		if (!ret && (header.sector == sector)) {
+		if (swim_read_sector_header(base, &header) ||
+		    swim_read(base, error) || header.track != track ||
+		    header.side != side || header.size != 2)
+			continue;
+		if (header.sector == sector) {
 			/* found */
 
 			ret = swim_read_sector_data(base, buffer);
+			if (swim_read(base, error))
+				ret = -EIO;
 			break;
 		}
 	}
 	local_irq_restore(flags);
 
-	if ((header.side != side)  || (header.track != track) ||
-	     (header.sector != sector))
-		return 0;
-
 	return ret;
 }
 
diff --git a/drivers/block/swim_asm.S b/drivers/block/swim_asm.S
index 533e3bf02fa9..aa61ecc1af96 100644
--- a/drivers/block/swim_asm.S
+++ b/drivers/block/swim_asm.S
@@ -67,7 +67,6 @@ mfm_read_addrmark:
 	movew	#seek_time, %d2
 
 wait_header_init:
-	tstb	%a3@(read_error - read_mark)
 	moveb	#0x18, %a3@(write_mode0 - read_mark)
 	moveb	#0x01, %a3@(write_mode1 - read_mark)
 	moveb	#0x01, %a3@(write_mode0 - read_mark)
@@ -140,8 +139,6 @@ crc1:	moveb	%a2@, %d5
 	andb	#.Lhr_crc_error, %d5
 	bne	signal_nonyb
 
-	tstb	%a3@(read_error - read_mark)
-
 	moveq	#0, %d0
 signal_nonyb:
 	moveb	#0x18, %a3@(write_mode0 - read_mark)
@@ -166,7 +163,6 @@ mfm_read_data:
 	movew	#seek_time, %d2
 
 wait_data_init:
-	tstb	%a3@(read_error - read_mark)
 	moveb	#0x18, %a3@(write_mode0 - read_mark)
 	moveb	#0x01, %a3@(write_mode1 - read_mark)
 	moveb	#0x01, %a3@(write_mode0 - read_mark)
@@ -191,8 +187,6 @@ wait_data_mark_byte:
 
 	/* read data */
 
-	tstb	%a3@(read_error - read_mark)
-
 	movel	#sector_size-1, %d4		/* sector size */
 read_new_data:
 	movew	#max_retry, %d2
@@ -234,8 +228,6 @@ data_crc1:
 	andb	#.Lhr_crc_error, %d5
 	bne	data_exit
 
-	tstb	%a3@(read_error - read_mark)
-
 	/* return number of bytes read */
 
 	movel	#sector_size, %d0
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 15/32] swim: Don't use the mark register to read data
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (18 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 02/32] swim: Select appropriate drive once only Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 22/32] swim: Remove pointless mode0 register write Finn Thain
                   ` (11 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

If an unexpected mark byte were to be read from the data register, an
error would be flagged. But no error gets flagged when such a byte is
read from the mark register, which is misleading. Always use the data
register except when a mark byte is expected.

Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim_asm.S | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/block/swim_asm.S b/drivers/block/swim_asm.S
index aa61ecc1af96..b12289bed2f0 100644
--- a/drivers/block/swim_asm.S
+++ b/drivers/block/swim_asm.S
@@ -47,11 +47,11 @@
 	.global swim_read_sector_header
 swim_read_sector_header:
 	link	%a6, #0
-	moveml	%d1-%d5/%a0-%a4,%sp@-
+	moveml	%d1-%d5/%a0-%a5,%sp@-
 	movel	%a6@(0x0c), %a4
 	moveq	#-1, %d0
 	bsr	mfm_read_addrmark
-	moveml	%sp@+, %d1-%d5/%a0-%a4
+	moveml	%sp@+, %d1-%d5/%a0-%a5
 	unlk	%a6
 	rts
 
@@ -63,6 +63,7 @@ sector_data_mark:
 mfm_read_addrmark:
 	movel	%a6@(0x08), %a3
 	lea	%a3@(read_handshake), %a2
+	lea	%a3@(read_data), %a5
 	lea	%a3@(read_mark), %a3
 	movew	#seek_time, %d2
 
@@ -93,7 +94,7 @@ amark0:	tstb	%a2@
 	dbmi	%d2, amark0
 	bpl	signal_nonyb
 
-	moveb	%a3@, %a4@(o_track)
+	moveb	%a5@, %a4@(o_track)
 
 	moveq	#max_retry, %d2
 
@@ -101,7 +102,7 @@ amark1:	tstb	%a2@
 	dbmi	%d2, amark1
 	bpl	signal_nonyb
 
-	moveb	%a3@, %a4@(o_side)
+	moveb	%a5@, %a4@(o_side)
 
 	moveq	#max_retry, %d2
 
@@ -109,7 +110,7 @@ amark2:	tstb	%a2@
 	dbmi	%d2, amark2
 	bpl	signal_nonyb
 
-	moveb	%a3@, %a4@(o_sector)
+	moveb	%a5@, %a4@(o_sector)
 
 	moveq	#max_retry, %d2
 
@@ -117,7 +118,7 @@ amark3:	tstb	%a2@
 	dbmi	%d2, amark3
 	bpl	signal_nonyb
 
-	moveb	%a3@, %a4@(o_size)
+	moveb	%a5@, %a4@(o_size)
 
 	moveq	#max_retry, %d2
 
@@ -125,7 +126,7 @@ crc0:	tstb	%a2@
 	dbmi	%d2, crc0
 	bpl	signal_nonyb
 
-	moveb	%a3@, %a4@(o_crc0)
+	moveb	%a5@, %a4@(o_crc0)
 
 	moveq	#max_retry, %d2
 
@@ -133,7 +134,7 @@ crc1:	moveb	%a2@, %d5
 	dbmi	%d2, crc1
 	bpl	signal_nonyb
 
-	moveb	%a3@, %a4@(o_crc1)
+	moveb	%a5@, %a4@(o_crc1)
 
 	moveb	%a2@, %d5
 	andb	#.Lhr_crc_error, %d5
@@ -212,7 +213,7 @@ data_crc0:
 	dbmi	%d2, data_crc0
 	bpl	data_exit
 
-	moveb	%a3@, %d2
+	moveb	%a5@, %d2
 
 	moveq	#max_retry, %d2
 
@@ -222,7 +223,7 @@ data_crc1:
 	dbmi	%d2, data_crc1
 	bpl	data_exit
 
-	moveb	%a3@, %d2
+	moveb	%a5@, %d2
 
 	moveb	%a2@, %d5
 	andb	#.Lhr_crc_error, %d5
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 16/32] swim: Fix buffer overflow
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (5 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 20/32] swim: Check drive ready bit Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 27/32] swim: Add some helpful references Finn Thain
                   ` (24 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

The effect of this bug can be observed as swim_read_sector_data()
inexplicably returning -5, or an error flag indicating that a mark byte
was read from the data register, or other odd behviour.

When copying bytes from the chip FIFO to the read buffer, the driver
keeps count of the remaining buffer space using register %d4. A counter
in register %d2 serves as a timeout. The driver polls (%a2), the handshake
register, until flags indicate that byte(s) have arrived in the FIFO.

        movel   #sector_size-1, %d4
read_new_data:
        movew   #max_retry, %d2
read_data_loop:
        moveb   %a2@, %d5
        andb    #0xc0, %d5
        dbne    %d2, read_data_loop
        beq     data_exit
        moveb   %a5@, %a4@+
        andb    #0x40, %d5
        dbne    %d4, read_new_data
        beq     exit_loop

Note that the exit_loop branch depends upon a flag in the handshake
register and not on the remaining buffer space. Hence there may be no
branch to exit_loop after %d4 is decremented to -1 (i.e. full buffer).

        moveb   %a5@, %a4@+
        dbra    %d4, read_new_data
exit_loop:

Here is a second decrement of %d4 which can now reach -2. But the buffer
bounds check is a comparison with -1, which is now ineffective. Hence the
loop will continue copying until %d2 eventually reaches -1.

Fix this bug by terminating the loop as soon as %d4 or %d2 reach -1.
Reset the timeout whenever a byte is copied.

Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
Changed since v1:
 - Avoid jumping to a redundant AND.B.
 - Avoid a second handshake register access when there's already a byte in
 the FIFO.
---
 drivers/block/swim_asm.S | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/block/swim_asm.S b/drivers/block/swim_asm.S
index b12289bed2f0..9a7d7466e846 100644
--- a/drivers/block/swim_asm.S
+++ b/drivers/block/swim_asm.S
@@ -43,6 +43,8 @@
 	.equ	sector_size, 512
 
 	.equ	.Lhr_crc_error,		0x02
+	.equ	.Lhr_fifo_2bytes,	0x40
+	.equ	.Lhr_fifo_1byte,	0x80
 
 	.global swim_read_sector_header
 swim_read_sector_header:
@@ -189,20 +191,20 @@ wait_data_mark_byte:
 	/* read data */
 
 	movel	#sector_size-1, %d4		/* sector size */
-read_new_data:
 	movew	#max_retry, %d2
 read_data_loop:
 	moveb	%a2@, %d5
-	andb	#0xc0, %d5
+	andb	#(.Lhr_fifo_1byte + .Lhr_fifo_2bytes), %d5
 	dbne	%d2, read_data_loop
 	beq	data_exit
+	moveq	#max_retry, %d2
 	moveb	%a5@, %a4@+
-	andb	#0x40, %d5
-	dbne	%d4, read_new_data
-	beq	exit_loop
+	dbra	%d4, 1f
+	bra	data_crc0
+1:	andb	#.Lhr_fifo_2bytes, %d5
+	beq	read_data_loop
 	moveb	%a5@, %a4@+
-	dbra	%d4, read_new_data
-exit_loop:
+	dbra	%d4, read_data_loop
 
 	/* read CRC */
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 17/32] swim: Convert to blocking queue
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (27 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 10/32] swim: Add track zero recalibration delay Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 06/32] swim: Configure parameter memory Finn Thain
                   ` (2 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel, Omar Sandoval

These drives are slow: completing a request can take hundreds of
milliseconds. Delays are managed by disabling interrupts judiciously and
sleeping opportunistically.

As of commit e3896d77b702 ("swim: convert to blk-mq"), a spinlock is
taken in irq mode as soon as a request is issued. That lock is held for
the duration of the request. Hence the driver sleeps while holding the
lock which is forbidden.

Adopt BLK_MQ_F_BLOCKING and remove the spinlock. Use a mutex to serialize
requests from the two request queues. (The chip cannot simultaneously
process requests on both internal and external drive.)

Cc: Omar Sandoval <osandov@fb.com>
Fixes: e3896d77b702 ("swim: convert to blk-mq")
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 11 +++--------
 1 file changed, 3 insertions(+), 8 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 33374498d621..8c8b157e2d74 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -211,7 +211,6 @@ enum head {
 
 struct swim_priv {
 	struct swim __iomem *base;
-	spinlock_t lock;
 	int floppy_count;
 	struct floppy_state unit[FD_MAX_UNIT];
 };
@@ -537,12 +536,10 @@ static blk_status_t swim_queue_rq(struct blk_mq_hw_ctx *hctx,
 				  const struct blk_mq_queue_data *bd)
 {
 	struct floppy_state *fs = hctx->queue->queuedata;
-	struct swim_priv *swd = fs->swd;
 	struct request *req = bd->rq;
 	blk_status_t err;
 
-	if (!spin_trylock_irq(&swd->lock))
-		return BLK_STS_DEV_RESOURCE;
+	mutex_lock(&swim_mutex);
 
 	blk_mq_start_request(req);
 
@@ -560,7 +557,7 @@ static blk_status_t swim_queue_rq(struct blk_mq_hw_ctx *hctx,
 
 	err = BLK_STS_OK;
 out:
-	spin_unlock_irq(&swd->lock);
+	mutex_unlock(&swim_mutex);
 	return err;
 
 }
@@ -841,11 +838,9 @@ static int swim_floppy_init(struct platform_device *pdev)
 		return -EBUSY;
 	}
 
-	spin_lock_init(&swd->lock);
-
 	for (drive = 0; drive < swd->floppy_count; drive++) {
 		err = blk_mq_alloc_sq_tag_set(&swd->unit[drive].tag_set,
-				&swim_mq_ops, 2, 0);
+				&swim_mq_ops, 2, BLK_MQ_F_BLOCKING);
 		if (err)
 			goto exit_put_disks;
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 18/32] swim: Remove redundant RELAX actions
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (22 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 05/32] swim: Perform ISM/IWM mode switching according to specs Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 29/32] swim: Clean up whitespace Finn Thain
                   ` (7 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

Wherever we have a swim_select() or swim_readbit() call there is an
implicit RELAX. That means the caller doesn't have to do it. Remove the
redundant code.

BTW, Inside Macintosh says, "Be sure [...] that CA0 and CA1 are set high
before changing SEL." Hence the RELAX found in swim_select(). The SwimIII
driver in mkLinux also has that. But the swim3.c driver in Linux is odd:
it scatters RELAX actions around as though SEL was not actually under its
control... In anycase, swim.c really does control SEL so there's no need
for that here.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 8c8b157e2d74..9635f4df3fc0 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -336,7 +336,6 @@ static inline void swim_motor(struct swim __iomem *base,
 		swim_action(base, MOTOR_ON);
 
 		for (i = 0; i < 2*HZ; i++) {
-			swim_select(base, RELAX);
 			if (swim_readbit(base, MOTOR_ON))
 				break;
 			set_current_state(TASK_INTERRUPTIBLE);
@@ -344,7 +343,7 @@ static inline void swim_motor(struct swim __iomem *base,
 		}
 	} else if (action == OFF) {
 		swim_action(base, MOTOR_OFF);
-		swim_select(base, RELAX);
+		swim_write(base, phase, RELAX | PHASE_PIN_DIR);
 	}
 }
 
@@ -355,13 +354,11 @@ static inline void swim_eject(struct swim __iomem *base)
 	swim_action(base, EJECT);
 
 	for (i = 0; i < 2*HZ; i++) {
-		swim_select(base, RELAX);
 		if (!swim_readbit(base, DISK_IN))
 			break;
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(1);
 	}
-	swim_select(base, RELAX);
 }
 
 static inline void swim_head(struct swim __iomem *base, enum head head)
@@ -385,7 +382,6 @@ static inline int swim_step(struct swim __iomem *base)
 		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(1);
 
-		swim_select(base, RELAX);
 		if (!swim_readbit(base, STEP))
 			return 0;
 	}
@@ -399,8 +395,6 @@ static inline int swim_track00(struct swim __iomem *base)
 	swim_action(base, SEEK_NEGATIVE);
 
 	for (try = 0; try < 100; try++) {
-
-		swim_select(base, RELAX);
 		msleep(3);
 
 		if (swim_readbit(base, TRACK_ZERO))
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 19/32] swim: Deduplicate polling loops
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (7 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 27/32] swim: Add some helpful references Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 04/32] swim: Don't disable drive after every sector Finn Thain
                   ` (22 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

Replace duplicated polling loops with poll_timeout_us(). Change the
interruptible sleep to uninterruptible because signal delivery shouldn't
be allowed to shorten delays required by the drive hardware.

Change the timeout for the !STEP transition to 20 ms in accordance with
the maximum interval required by the UPD72070 spec. The existing 1 second
timeout is impractical considering the number of steps in a typical seek.

Change the return type of swim_readbit() to bool because that way the
bit names make sense i.e. the reader doesn't have to remember to invert
the active-low logic used for drive signals.

Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
Changed since v1:
 - Dropped swim_readbit_timeout_atomic() as it's no longer needed.
---
 drivers/block/swim.c | 39 ++++++++-------------------------------
 1 file changed, 8 insertions(+), 31 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 9635f4df3fc0..36e28a766a5a 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -19,6 +19,7 @@
 #include <linux/major.h>
 #include <linux/mutex.h>
 #include <linux/hdreg.h>
+#include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
@@ -296,7 +297,7 @@ static inline void swim_action(struct swim __iomem *base, int action)
 	local_irq_restore(flags);
 }
 
-static inline int swim_readbit(struct swim __iomem *base, int bit)
+static inline bool swim_readbit(struct swim __iomem *base, int bit)
 {
 	int stat;
 
@@ -309,6 +310,9 @@ static inline int swim_readbit(struct swim __iomem *base, int bit)
 	return (stat & SENSE) == 0;
 }
 
+#define swim_readbit_timeout(base, bit, val, timeout_us) \
+	poll_timeout_us(, swim_readbit(base, bit) == val, 1000, timeout_us, false)
+
 static inline void swim_drive(struct swim __iomem *base,
 			      enum drive_location location)
 {
@@ -331,16 +335,8 @@ static inline void swim_motor(struct swim __iomem *base,
 			      enum motor_action action)
 {
 	if (action == ON) {
-		int i;
-
 		swim_action(base, MOTOR_ON);
-
-		for (i = 0; i < 2*HZ; i++) {
-			if (swim_readbit(base, MOTOR_ON))
-				break;
-			set_current_state(TASK_INTERRUPTIBLE);
-			schedule_timeout(1);
-		}
+		swim_readbit_timeout(base, MOTOR_ON, true, 2000 * 1000);
 	} else if (action == OFF) {
 		swim_action(base, MOTOR_OFF);
 		swim_write(base, phase, RELAX | PHASE_PIN_DIR);
@@ -349,16 +345,8 @@ static inline void swim_motor(struct swim __iomem *base,
 
 static inline void swim_eject(struct swim __iomem *base)
 {
-	int i;
-
 	swim_action(base, EJECT);
-
-	for (i = 0; i < 2*HZ; i++) {
-		if (!swim_readbit(base, DISK_IN))
-			break;
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(1);
-	}
+	swim_readbit_timeout(base, DISK_IN, false, 2000 * 1000);
 }
 
 static inline void swim_head(struct swim __iomem *base, enum head head)
@@ -373,19 +361,8 @@ static inline void swim_head(struct swim __iomem *base, enum head head)
 
 static inline int swim_step(struct swim __iomem *base)
 {
-	int wait;
-
 	swim_action(base, STEP);
-
-	for (wait = 0; wait < HZ; wait++) {
-
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(1);
-
-		if (!swim_readbit(base, STEP))
-			return 0;
-	}
-	return -1;
+	return swim_readbit_timeout(base, STEP, false, 20 * 1000);
 }
 
 static inline int swim_track00(struct swim __iomem *base)
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 20/32] swim: Check drive ready bit
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (4 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 12/32] swim: Simplify return value initialization Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 16/32] swim: Fix buffer overflow Finn Thain
                   ` (25 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

The drive provides a readiness signal that has to be tested before
certain commands are issued to the drive. Rename the SEEK_COMPLETE flag
as READY because that's how it's known in the documentation as well as
the mkLinux source code.

Poll for that signal after stepping the heads and also after switching
to MFM mode, as that's what mkLinux does. Check for readiness when
stepping because testing shows that some drives require this.

Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 29 ++++++++++++++++++++++-------
 1 file changed, 22 insertions(+), 7 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 36e28a766a5a..987e43e5b4ef 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -117,7 +117,7 @@ struct iwm {
 #define TACHO		0x103
 #define READ_DATA_1	0x104
 #define GCR_MODE	0x105
-#define SEEK_COMPLETE	0x106
+#define READY		0x106
 #define TWOMEG_MEDIA	0x107
 
 /* Bits in handshake register */
@@ -313,6 +313,14 @@ static inline bool swim_readbit(struct swim __iomem *base, int bit)
 #define swim_readbit_timeout(base, bit, val, timeout_us) \
 	poll_timeout_us(, swim_readbit(base, bit) == val, 1000, timeout_us, false)
 
+#define swim_READY_timeout(base) \
+({ \
+	int ret = swim_readbit_timeout(base, READY, true, 1000 * 1000); \
+	if (ret) \
+		printk(KERN_DEBUG "%s: drive not ready\n", __func__); \
+	ret; \
+})
+
 static inline void swim_drive(struct swim __iomem *base,
 			      enum drive_location location)
 {
@@ -351,8 +359,6 @@ static inline void swim_eject(struct swim __iomem *base)
 
 static inline void swim_head(struct swim __iomem *base, enum head head)
 {
-	/* wait drive is ready */
-
 	if (head == UPPER_HEAD)
 		swim_select(base, READ_DATA_1);
 	else if (head == LOWER_HEAD)
@@ -387,20 +393,25 @@ static inline int swim_track00(struct swim __iomem *base)
 
 static inline int swim_seek(struct swim __iomem *base, int step)
 {
-	if (step == 0)
-		return 0;
-
 	if (step < 0) {
 		swim_action(base, SEEK_NEGATIVE);
 		step = -step;
-	} else
+	} else if (step > 0)
 		swim_action(base, SEEK_POSITIVE);
 
+	swim_READY_timeout(base);
+
+	if (step == 0)
+		return 0;
+
 	for ( ; step > 0; step--) {
 		if (swim_step(base))
 			return -1;
 	}
 
+	msleep(30);
+	swim_READY_timeout(base);
+
 	return 0;
 }
 
@@ -482,6 +493,8 @@ static blk_status_t floppy_read_sectors(struct floppy_state *fs,
 
 
 	swim_drive(base, fs->location);
+	swim_READY_timeout(base);
+
 	for (i = req_sector; i < req_sector + sectors_nb; i++) {
 		int x;
 		track = i / fs->secpercyl;
@@ -602,6 +615,8 @@ static int floppy_open(struct gendisk *disk, blk_mode_t mode)
 
 	swim_motor(base, ON);
 	swim_action(base, SETMFM);
+	msleep(30);
+	swim_READY_timeout(base);
 
 	set_capacity(fs->disk, fs->total_secs);
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 21/32] swim: Revisit delays
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (25 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 14/32] swim: Check error register during sector read Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 10/32] swim: Add track zero recalibration delay Finn Thain
                   ` (4 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

AFAIK, timing requirements for the various FDHD drive mechanisms aren't
well documented. But we do have the UPD72070 spec and secondary sources
like swim3.c and mkLinux source code. This patch is needed to satisfy
the requirements in the UPD72070 spec and follows mkLinux.

Change the LSTRB pulse to 2 microseconds, because this is what mkLinux
does. Inside Macintosh says, "Hold LSTRB high for at least one usec but
not more than one msec".

When a disk is ejected, pause before de-asserting /ENBL. Wait 150 us after
the STEP command for valid signalling. Pause for 1 us after setting the
step direction before sending the STEP command.

Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 987e43e5b4ef..eb4c2b7c57e7 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -290,7 +290,7 @@ static inline void swim_action(struct swim __iomem *base, int action)
 	swim_select(base, action);
 	udelay(1);
 	swim_write(base, phase, LSTRB | action | PHASE_PIN_DIR);
-	udelay(1);
+	udelay(2);
 	swim_write(base, phase, action | PHASE_PIN_DIR);
 	udelay(1);
 
@@ -337,6 +337,7 @@ static inline void swim_drive(struct swim __iomem *base,
 		swim_write(base, mode0, EXTERNAL_DRIVE);
 		swim_write(base, mode0, MOTON);
 	}
+	udelay(1);
 }
 
 static inline void swim_motor(struct swim __iomem *base,
@@ -355,6 +356,7 @@ static inline void swim_eject(struct swim __iomem *base)
 {
 	swim_action(base, EJECT);
 	swim_readbit_timeout(base, DISK_IN, false, 2000 * 1000);
+	msleep(1);
 }
 
 static inline void swim_head(struct swim __iomem *base, enum head head)
@@ -368,6 +370,7 @@ static inline void swim_head(struct swim __iomem *base, enum head head)
 static inline int swim_step(struct swim __iomem *base)
 {
 	swim_action(base, STEP);
+	udelay(150);
 	return swim_readbit_timeout(base, STEP, false, 20 * 1000);
 }
 
@@ -398,6 +401,7 @@ static inline int swim_seek(struct swim __iomem *base, int step)
 		step = -step;
 	} else if (step > 0)
 		swim_action(base, SEEK_POSITIVE);
+	udelay(1);
 
 	swim_READY_timeout(base);
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 22/32] swim: Remove pointless mode0 register write
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (19 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 15/32] swim: Don't use the mark register to read data Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 30/32] swim: Define macros for constants Finn Thain
                   ` (10 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

This write has no effect so remove it. (If side == 0 then no mode bit gets
cleared. If side == 1 then mode bit 0 gets cleared but that's pointless
because that bit is already clear here.)

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index eb4c2b7c57e7..38b1643f3702 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -464,7 +464,6 @@ static inline int swim_read_sector(struct floppy_state *fs,
 
 	swim_track(fs, track);
 	swim_head(base, side);
-	swim_write(base, mode0, side);
 
 	local_irq_save(flags);
 	for (i = 0; i < 36; i++) {
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 23/32] swim: Don't needlessly re-read sectors
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
  2026-08-17  1:17 ` [PATCH v2 26/32] swim: Move swd initialization Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 01/32] swim: Assert strobe with stable outputs Finn Thain
                   ` (29 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

floppy_read_sectors() is confusing because the `track' variable seems to
conflate tracks and cylinders. Rename this variable, eliminate a division
operation and adopt suitable integer types.

For readahead to work effectively, small sequential reads should not
require waiting for spindle rotation. Unfortunately, the present algorithm
is very inefficient and does a lot of unnecessary waiting.

E.g. if the device is asked to read sectors 1 thru 16, and if sector 9
happens to be under the heads, the driver will proceed to read sectors 9
thru 18, but discard the results, while it waits for sector 1 to arrive.

If sector 1 couldn't be read on the first attempt and needs a retry, the
driver will proceed to read sectors 2 thru 18, but discard the results,
while it waits for sector 1 to come around again.

In between reading sector 1 and sector 2, the driver needlessly calls
swim_track() and swim_head() again. But what's worse is re-enabling
interrupts after each sector, because on a 68030 system this can result
in a full rotation between sectors (which is a 3 ms wait).

Floppy drivers usually implement a track cache that can be filled in a
single rotation to solve problems like these. But I think there is a
simpler solution.

After stepping the heads, use a sector bitmap to record sectors that were
successfully read from the present track. Read (or retry, if need be)
requested sectors in whatever sequence they become available. Keep
interrupts disabled until the whole track has passed under the read head.

swim_read_sector() assumes that it can search a whole track by reading a
fixed number of sector headers (essentially, fs->secpertrack) but this
assumes no false sector headers are found in the sector contents. To
prevent that, call swim_read_sector_data() unconditionally after a valid
sector header is found.

Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
Changed since v1:
 - Use GENMASK() macro.
 - Use fs->secpertrack instead of hard-coding the high-density value.
 - Don't use a failure counter.
 - Use unsigned integers where appropriate.
 - Call swim_read_sector_data() whenever swim_read_sector_header() is
   successful. A NULL pointer is passed to indicate that no data is to be
   copied into the buffer.
---
 drivers/block/swim.c     | 96 ++++++++++++++++++++++------------------
 drivers/block/swim_asm.S | 12 ++++-
 2 files changed, 62 insertions(+), 46 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 38b1643f3702..e35918bdf9d2 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -180,9 +180,9 @@ struct floppy_state {
 	enum media_type	 type;
 	int		 write_protected;
 
-	int		 total_secs;
-	int		 secpercyl;
-	int		 secpertrack;
+	unsigned int	 total_secs;
+	unsigned int	 secpercyl;
+	unsigned int	 secpertrack;
 
 	/* in-use information */
 
@@ -452,68 +452,76 @@ static int floppy_eject(struct floppy_state *fs)
 	return 0;
 }
 
-static inline int swim_read_sector(struct floppy_state *fs,
-				   int side, int track,
-				   int sector, unsigned char *buffer)
+static unsigned int swim_read_sector_range(struct floppy_state *fs,
+					unsigned int side, unsigned int track,
+					unsigned int start, unsigned int count,
+					unsigned char *buffer)
 {
 	struct swim __iomem *base = fs->swd->base;
 	unsigned long flags;
 	struct sector_header header;
-	int ret = -1;
-	short i;
+	unsigned int i, bits = 0;
 
-	swim_track(fs, track);
-	swim_head(base, side);
+	if (count > 0) {
+		count = min(count, fs->secpertrack);
+		bits = GENMASK(count - 1, 0);
+	}
 
 	local_irq_save(flags);
-	for (i = 0; i < 36; i++) {
-		if (swim_read_sector_header(base, &header) ||
-		    swim_read(base, error) || header.track != track ||
-		    header.side != side || header.size != 2)
-			continue;
-		if (header.sector == sector) {
-			/* found */
-
-			ret = swim_read_sector_data(base, buffer);
-			if (swim_read(base, error))
-				ret = -EIO;
+	for (i = 0; i < 5 * fs->secpertrack; i++) {
+		if (bits == 0) /* All sectors were read ok */
 			break;
+
+		if (swim_read_sector_header(base, &header) == 0 &&
+		    swim_read(base, error) == 0) {
+			unsigned int offset = header.sector - start;
+			unsigned char *buf = NULL;
+			int len;
+
+			if (header.track == track && header.side == side &&
+			    header.size == 2 && header.sector >= start &&
+			    header.sector < start + count &&
+			    (bits & BIT(offset)))
+				buf = buffer + 512 * offset;
+			len = swim_read_sector_data(base, buf);
+			if (swim_read(base, error) == 0 && buf && len == 512)
+				bits &= ~BIT(offset);
 		}
 	}
 	local_irq_restore(flags);
 
-	return ret;
+	return bits ? ffs(bits) - 1 : count; /* No. of contiguous ok sectors */
 }
 
 static blk_status_t floppy_read_sectors(struct floppy_state *fs,
-			       int req_sector, int sectors_nb,
-			       unsigned char *buffer)
+					unsigned int req_sector,
+					unsigned int sectors_nb,
+					unsigned char *buffer)
 {
 	struct swim __iomem *base = fs->swd->base;
-	int ret;
-	int side, track, sector;
-	int i, try;
-
 
 	swim_drive(base, fs->location);
 	swim_READY_timeout(base);
 
-	for (i = req_sector; i < req_sector + sectors_nb; i++) {
-		int x;
-		track = i / fs->secpercyl;
-		x = i % fs->secpercyl;
-		side = x / fs->secpertrack;
-		sector = x % fs->secpertrack + 1;
-
-		try = 5;
-		do {
-			ret = swim_read_sector(fs, side, track, sector,
-						buffer);
-			if (try-- == 0)
-				return BLK_STS_IOERR;
-		} while (ret != 512);
-
-		buffer += ret;
+	while (sectors_nb) {
+		unsigned int cyl, x, head, sector, n, n_ok;
+
+		cyl = req_sector / fs->secpercyl;
+		x = req_sector % fs->secpercyl;
+		head = (x >= fs->secpertrack) ? 1 : 0;
+		sector = x % fs->secpertrack;
+		n = min(sectors_nb, fs->secpertrack - sector);
+
+		swim_track(fs, cyl);
+		swim_head(base, head);
+
+		n_ok = swim_read_sector_range(fs, head, cyl, sector + 1, n, buffer);
+		if (n_ok != n)
+			return BLK_STS_IOERR;
+
+		buffer += 512 * n;
+		sectors_nb -= n;
+		req_sector += n;
 	}
 
 	return 0;
diff --git a/drivers/block/swim_asm.S b/drivers/block/swim_asm.S
index 9a7d7466e846..10f4c42ee3ab 100644
--- a/drivers/block/swim_asm.S
+++ b/drivers/block/swim_asm.S
@@ -198,12 +198,14 @@ read_data_loop:
 	dbne	%d2, read_data_loop
 	beq	data_exit
 	moveq	#max_retry, %d2
-	moveb	%a5@, %a4@+
+	moveb	%a5@, %d3
+	bsr	.Lmaybe_store
 	dbra	%d4, 1f
 	bra	data_crc0
 1:	andb	#.Lhr_fifo_2bytes, %d5
 	beq	read_data_loop
-	moveb	%a5@, %a4@+
+	moveb	%a5@, %d3
+	bsr	.Lmaybe_store
 	dbra	%d4, read_data_loop
 
 	/* read CRC */
@@ -240,3 +242,9 @@ data_crc1:
 data_exit:
 	moveb	#0x18, %a3@(write_mode0 - read_mark)
 	rts
+
+.Lmaybe_store:
+	tstl	%a4
+	beq	9f
+	moveb	%d3, %a4@+
+9:	rts
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 24/32] swim: Don't search beyond the first data mark
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (12 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 32/32] swim: Unexport global symbols Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 03/32] swim: Enable the drive when probing Finn Thain
                   ` (17 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

The ISM chip does an automatic MFM gap/sync search when the Action bit
is first set. That search may stop at any of a) post-index gap, b) address
field gap or c) data field gap. To find the next sector header, the
driver need not search at all. It only has to validate the mark bytes.

Once the sector address mark has been validated, swim_read_sector_data()
is called to read the sector contents. Between the sector address and
data fields lies an intra-sector gap followed by a data field mark.
After this mark is validated, the 512-byte data area is read into the
IO request buffer.

Problem is, if any byte in the data field mark is mis-read, the driver
searches the whole sector and then reaches the data field mark in the
following sector. The wrong sector is then read into the buffer, and
swim_read_sector_data() returns success. The request is silently
corrupted.

The existing limit on polling loop iterations does constrain the search
distance but is inherently tied to CPU speed. This is probably the reason
why corruption was only observed on a 68030 system.

Discontinue the mark search when the mark bytes fail validation.

Fixes: 8852ecd97488 ("m68k: mac - Add SWIM floppy support")
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim_asm.S | 73 ++++++++++++++++++++++------------------
 1 file changed, 40 insertions(+), 33 deletions(-)

diff --git a/drivers/block/swim_asm.S b/drivers/block/swim_asm.S
index 10f4c42ee3ab..4913470b63e8 100644
--- a/drivers/block/swim_asm.S
+++ b/drivers/block/swim_asm.S
@@ -41,18 +41,45 @@
 	.equ	seek_time, 30000
 	.equ	max_retry, 40
 	.equ	sector_size, 512
+	.equ	.Lmark_sequence_len,	4
 
 	.equ	.Lhr_crc_error,		0x02
 	.equ	.Lhr_fifo_2bytes,	0x40
 	.equ	.Lhr_fifo_1byte,	0x80
 
+.Lmfm_mark_check:
+	/*
+	 * This subroutine reads and validates a mark byte sequence.
+	 * On entry, %a1 and %d4 shall hold the location and length (resp.)
+	 * of the mark byte array.
+	 * %a2 and %a3 shall hold the locations of the handshake and mark
+	 * registers.
+	 * Returns zero in %d1 for success.
+	 */
+
+	moveq	#-1, %d1
+	subq	#1, %d4
+	movew	#seek_time, %d2
+
+5:	tstb	%a2@
+	dbmi	%d2, 5b
+	bpl	6f
+
+	moveb	%a3@, %d3
+	cmpb	%a1@+, %d3
+	dbne	%d4, 5b
+	bne	6f
+
+	moveq	#0, %d1
+6:	rts
+
 	.global swim_read_sector_header
 swim_read_sector_header:
 	link	%a6, #0
 	moveml	%d1-%d5/%a0-%a5,%sp@-
 	movel	%a6@(0x0c), %a4
 	moveq	#-1, %d0
-	bsr	mfm_read_addrmark
+	bsr	.Lmfm_read_header
 	moveml	%sp@+, %d1-%d5/%a0-%a5
 	unlk	%a6
 	rts
@@ -62,33 +89,25 @@ sector_address_mark:
 sector_data_mark:
 	.byte	0xa1, 0xa1, 0xa1, 0xfb
 
-mfm_read_addrmark:
+.Lmfm_read_header:
 	movel	%a6@(0x08), %a3
 	lea	%a3@(read_handshake), %a2
 	lea	%a3@(read_data), %a5
 	lea	%a3@(read_mark), %a3
-	movew	#seek_time, %d2
 
-wait_header_init:
 	moveb	#0x18, %a3@(write_mode0 - read_mark)
 	moveb	#0x01, %a3@(write_mode1 - read_mark)
 	moveb	#0x01, %a3@(write_mode0 - read_mark)
 	tstb	%a3@(read_error - read_mark)
 	moveb	#0x08, %a3@(write_mode1 - read_mark)
 
-	lea	sector_address_mark, %a0
-	moveq	#3, %d1
-
-wait_addr_mark_byte:
-
-	tstb	%a2@
-	dbmi	%d2, wait_addr_mark_byte
-	bpl	signal_nonyb
+	lea	sector_address_mark, %a1
+	moveq	#.Lmark_sequence_len, %d4
+	bsr	.Lmfm_mark_check
+	tstl	%d1
+	bne	signal_nonyb
 
-	moveb	%a3@, %d3
-	cmpb	%a0@+, %d3
-	dbne	%d1, wait_addr_mark_byte
-	bne	wait_header_init
+	/* read header */
 
 	moveq	#max_retry, %d2
 
@@ -163,30 +182,18 @@ mfm_read_data:
 	lea	%a3@(read_handshake), %a2
 	lea	%a3@(read_data), %a5
 	lea	%a3@(read_mark), %a3
-	movew	#seek_time, %d2
 
-wait_data_init:
 	moveb	#0x18, %a3@(write_mode0 - read_mark)
 	moveb	#0x01, %a3@(write_mode1 - read_mark)
 	moveb	#0x01, %a3@(write_mode0 - read_mark)
 	tstb	%a3@(read_error - read_mark)
 	moveb	#0x08, %a3@(write_mode1 - read_mark)
 
-	lea	sector_data_mark, %a0
-	moveq	#3, %d1
-
-	/* wait data address mark */
-
-wait_data_mark_byte:
-
-	tstb	%a2@
-	dbmi	%d2, wait_data_mark_byte
-	bpl	data_exit
-
-	moveb	%a3@, %d3
-	cmpb	%a0@+, %d3
-	dbne	%d1, wait_data_mark_byte
-	bne	wait_data_init
+	lea	sector_data_mark, %a1
+	moveq	#.Lmark_sequence_len, %d4
+	bsr	.Lmfm_mark_check
+	tstl	%d1
+	bne	data_exit
 
 	/* read data */
 
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 25/32] swim: Remove pointless specifiers
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (15 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 13/32] swim: Check for CRC errors Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 08/32] swim: Don't start motor until medium is present Finn Thain
                   ` (14 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

If the compiler made these functions "as fast as possible" that wouldn't
actually help because they involve slow mechanical operations. Remove
pointless inline function specifiers.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index e35918bdf9d2..ae31b302dac4 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -222,7 +222,7 @@ extern int swim_read_sector_data(struct swim __iomem *base,
 				 unsigned char *data);
 
 static DEFINE_MUTEX(swim_mutex);
-static inline void set_swim_mode(struct swim __iomem *base, int enable)
+static void set_swim_mode(struct swim __iomem *base, int enable)
 {
 	struct iwm __iomem *iwm_base = (struct iwm __iomem *)base;
 	unsigned long flags;
@@ -250,7 +250,7 @@ static inline void set_swim_mode(struct swim __iomem *base, int enable)
 	local_irq_restore(flags);
 }
 
-static inline int get_swim_mode(struct swim __iomem *base)
+static int get_swim_mode(struct swim __iomem *base)
 {
 	unsigned long flags;
 
@@ -321,7 +321,7 @@ static inline bool swim_readbit(struct swim __iomem *base, int bit)
 	ret; \
 })
 
-static inline void swim_drive(struct swim __iomem *base,
+static void swim_drive(struct swim __iomem *base,
 			      enum drive_location location)
 {
 	if (location == INTERNAL_DRIVE) {
@@ -340,8 +340,8 @@ static inline void swim_drive(struct swim __iomem *base,
 	udelay(1);
 }
 
-static inline void swim_motor(struct swim __iomem *base,
-			      enum motor_action action)
+static void swim_motor(struct swim __iomem *base,
+		       enum motor_action action)
 {
 	if (action == ON) {
 		swim_action(base, MOTOR_ON);
@@ -352,7 +352,7 @@ static inline void swim_motor(struct swim __iomem *base,
 	}
 }
 
-static inline void swim_eject(struct swim __iomem *base)
+static void swim_eject(struct swim __iomem *base)
 {
 	swim_action(base, EJECT);
 	swim_readbit_timeout(base, DISK_IN, false, 2000 * 1000);
@@ -367,14 +367,14 @@ static inline void swim_head(struct swim __iomem *base, enum head head)
 		swim_select(base, READ_DATA_0);
 }
 
-static inline int swim_step(struct swim __iomem *base)
+static int swim_step(struct swim __iomem *base)
 {
 	swim_action(base, STEP);
 	udelay(150);
 	return swim_readbit_timeout(base, STEP, false, 20 * 1000);
 }
 
-static inline int swim_track00(struct swim __iomem *base)
+static int swim_track00(struct swim __iomem *base)
 {
 	int try;
 
@@ -394,7 +394,7 @@ static inline int swim_track00(struct swim __iomem *base)
 	return -1;
 }
 
-static inline int swim_seek(struct swim __iomem *base, int step)
+static int swim_seek(struct swim __iomem *base, int step)
 {
 	if (step < 0) {
 		swim_action(base, SEEK_NEGATIVE);
@@ -419,7 +419,7 @@ static inline int swim_seek(struct swim __iomem *base, int step)
 	return 0;
 }
 
-static inline int swim_track(struct floppy_state *fs,  int track)
+static int swim_track(struct floppy_state *fs,  int track)
 {
 	struct swim __iomem *base = fs->swd->base;
 	int ret;
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 26/32] swim: Move swd initialization
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 23/32] swim: Don't needlessly re-read sectors Finn Thain
                   ` (30 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

For better readability, initialize the swd backpointer along with the
other floppy_state struct members. No functional change.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index ae31b302dac4..c204108c50f0 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -761,6 +761,7 @@ static void swim_add_floppy(struct swim_priv *swd, enum drive_location location)
 	if (swim_track00(base))
 		goto out;
 
+	fs->swd = swd;
 	fs->location = location;
 
 	fs->type = HD_MEDIA;
@@ -849,8 +850,6 @@ static int swim_floppy_init(struct platform_device *pdev)
 			err = PTR_ERR(swd->unit[drive].disk);
 			goto exit_put_disks;
 		}
-
-		swd->unit[drive].swd = swd;
 	}
 
 	for (drive = 0; drive < swd->floppy_count; drive++) {
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 27/32] swim: Add some helpful references
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (6 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 16/32] swim: Fix buffer overflow Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 19/32] swim: Deduplicate polling loops Finn Thain
                   ` (23 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

These documents relate to the IWM, ISM, SWIM 1, 2, 3 and associated
disk drives. No functional change.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index c204108c50f0..d7182f95c21d 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -8,6 +8,14 @@
  * based on SWIM3 driver (c) Paul Mackerras, 1996
  * based on netBSD IWM driver (c) 1997, 1998 Hauke Fath.
  *
+ * See also:
+ * Inside Macintosh, vol. III, ch. 2
+ * https://archive.org/details/SWIMDesignDocs
+ * NEC uPD72070 FDC datasheet
+ * mkLinux source file swimiiicommonhal.c
+ * http://www.mac.linux-m68k.org/devel/iwm.php.html
+ * MAME source file sonydriv.cpp
+ *
  * 2004-08-21 (lv) - Initial implementation
  * 2008-10-30 (lv) - Port to 2.6
  */
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 28/32] swim: Remove unused macro definitions
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (10 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 11/32] swim: Handle FIFO timeout error Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 32/32] swim: Unexport global symbols Finn Thain
                   ` (19 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

Also remove the horizontal rule at the end of the macro definitions as
it doesn't any add value, IMO.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index d7182f95c21d..aebebc7f5d60 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -130,25 +130,14 @@ struct iwm {
 
 /* Bits in handshake register */
 
-#define MARK_BYTE	0x01
-#define CRC_ZERO	0x02
-#define RDDATA		0x04
 #define SENSE		0x08
-#define MOTEN		0x10
-#define ERROR		0x20
 #define DAT2BYTE	0x40
 #define DAT1BYTE	0x80
 
 /* bits in setup register */
 
-#define S_INV_WDATA	0x01
-#define S_3_5_SELECT	0x02
-#define S_GCR		0x04
 #define S_FCLK_DIV2	0x08
-#define S_ERROR_CORR	0x10
 #define S_IBM_DRIVE	0x20
-#define S_GCR_WRITE	0x40
-#define S_TIMEOUT	0x80
 
 /* bits in mode register */
 
@@ -157,12 +146,9 @@ struct iwm {
 #define ENBL2		0x04
 #define ACTION		0x08
 #define WRITE_MODE	0x10
-#define HEDSEL		0x20
 #define ISM_SELECT	0x40
 #define MOTON		0x80
 
-/*----------------------------------------------------------------------------*/
-
 enum drive_location {
 	NO_DRIVE = 0,
 	INTERNAL_DRIVE = BIT(1),
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 29/32] swim: Clean up whitespace
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (23 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 18/32] swim: Remove redundant RELAX actions Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 14/32] swim: Check error register during sector read Finn Thain
                   ` (6 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

No functional changes.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c     | 46 +++++++++++++++++++++-------------------
 drivers/block/swim_asm.S | 14 +++---------
 2 files changed, 27 insertions(+), 33 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index aebebc7f5d60..73d11e827e5d 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -2,7 +2,7 @@
 /*
  * Driver for SWIM (Sander Woz Integrated Machine) floppy controller
  *
- * Copyright (C) 2004,2008 Laurent Vivier <Laurent@lvivier.info>
+ * Copyright (C) 2004, 2008 Laurent Vivier <Laurent@lvivier.info>
  *
  * based on Alastair Bridgewater SWIM analysis, 2001
  * based on SWIM3 driver (c) Paul Mackerras, 1996
@@ -69,7 +69,7 @@ struct swim {
 	REG(read_handshake)
 } __attribute__((packed));
 
-#define swim_write(base, reg, v) 	out_8(&(base)->write_##reg, (v))
+#define swim_write(base, reg, v)	out_8(&(base)->write_##reg, (v))
 #define swim_read(base, reg)		in_8(&(base)->read_##reg)
 
 /* IWM registers */
@@ -93,7 +93,7 @@ struct iwm {
 	REG(q7H)
 } __attribute__((packed));
 
-#define iwm_write(base, reg, v) 	out_8(&(base)->reg, (v))
+#define iwm_write(base, reg, v)		out_8(&(base)->reg, (v))
 #define iwm_read(base, reg)		in_8(&(base)->reg)
 
 /* Bits in phase register */
@@ -165,23 +165,23 @@ struct floppy_state {
 	/* physical properties */
 
 	enum drive_location location;	/* internal or external drive */
-	int		 head_number;	/* single- or double-sided drive */
+	int head_number;		/* single- or double-sided drive */
 
 	/* media */
 
-	int		 disk_in;
-	int		 ejected;
-	enum media_type	 type;
-	int		 write_protected;
+	int disk_in;
+	int ejected;
+	enum media_type type;
+	int write_protected;
 
-	unsigned int	 total_secs;
-	unsigned int	 secpercyl;
-	unsigned int	 secpertrack;
+	unsigned int total_secs;
+	unsigned int secpercyl;
+	unsigned int secpertrack;
 
 	/* in-use information */
 
-	int		track;
-	int		ref_count;
+	int track;
+	int ref_count;
 	bool registered;
 
 	struct gendisk *disk;
@@ -216,6 +216,7 @@ extern int swim_read_sector_data(struct swim __iomem *base,
 				 unsigned char *data);
 
 static DEFINE_MUTEX(swim_mutex);
+
 static void set_swim_mode(struct swim __iomem *base, int enable)
 {
 	struct iwm __iomem *iwm_base = (struct iwm __iomem *)base;
@@ -402,7 +403,7 @@ static int swim_seek(struct swim __iomem *base, int step)
 	if (step == 0)
 		return 0;
 
-	for ( ; step > 0; step--) {
+	for (; step > 0; step--) {
 		if (swim_step(base))
 			return -1;
 	}
@@ -413,7 +414,7 @@ static int swim_seek(struct swim __iomem *base, int step)
 	return 0;
 }
 
-static int swim_track(struct floppy_state *fs,  int track)
+static int swim_track(struct floppy_state *fs, int track)
 {
 	struct swim __iomem *base = fs->swd->base;
 	int ret;
@@ -552,10 +553,10 @@ static blk_status_t swim_queue_rq(struct blk_mq_hw_ctx *hctx,
 }
 
 static struct floppy_struct floppy_type[4] = {
-	{    0,  0, 0,  0, 0, 0x00, 0x00, 0x00, 0x00, NULL }, /* no testing   */
+	{    0,  0, 0,  0, 0, 0x00, 0x00, 0x00, 0x00, NULL }, /* no testing */
 	{  720,  9, 1, 80, 0, 0x2A, 0x02, 0xDF, 0x50, NULL }, /* 360KB SS 3.5"*/
-	{ 1440,  9, 2, 80, 0, 0x2A, 0x02, 0xDF, 0x50, NULL }, /* 720KB 3.5"   */
-	{ 2880, 18, 2, 80, 0, 0x1B, 0x00, 0xCF, 0x6C, NULL }, /* 1.44MB 3.5"  */
+	{ 1440,  9, 2, 80, 0, 0x2A, 0x02, 0xDF, 0x50, NULL }, /* 720KB 3.5" */
+	{ 2880, 18, 2, 80, 0, 0x1B, 0x00, 0xCF, 0x6C, NULL }, /* 1.44MB 3.5" */
 };
 
 static int get_floppy_geometry(struct floppy_state *fs, int type,
@@ -582,10 +583,11 @@ static void setup_medium(struct floppy_state *fs)
 
 	if (swim_readbit(base, DISK_IN)) {
 		struct floppy_struct *g;
+
 		fs->disk_in = 1;
 		fs->write_protected = swim_readbit(base, WRITE_PROT);
 		fs->type = swim_readbit(base, TWOMEG_MEDIA) ?
-			HD_MEDIA : DD_MEDIA;
+			   HD_MEDIA : DD_MEDIA;
 		fs->head_number = swim_readbit(base, SINGLE_SIDED) ? 1 : 2;
 		get_floppy_geometry(fs, 0, &g);
 		fs->total_secs = g->size;
@@ -687,7 +689,7 @@ static int floppy_ioctl(struct block_device *bdev, blk_mode_t mode,
 	int err;
 
 	if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
-			return -EPERM;
+		return -EPERM;
 
 	switch (cmd) {
 	case FDEJECT:
@@ -805,7 +807,7 @@ static int swim_floppy_init(struct platform_device *pdev)
 	struct swim_priv *swd = platform_get_drvdata(pdev);
 	unsigned int *data = pdev->dev.platform_data;
 	struct queue_limits lim = {
-		.features		= BLK_FEAT_ROTATIONAL,
+		.features = BLK_FEAT_ROTATIONAL,
 	};
 	int err;
 	int drive;
@@ -957,7 +959,7 @@ static void swim_remove(struct platform_device *dev)
 static struct platform_driver swim_driver = {
 	.probe  = swim_probe,
 	.remove = swim_remove,
-	.driver   = {
+	.driver = {
 		.name	= CARDNAME,
 	},
 };
diff --git a/drivers/block/swim_asm.S b/drivers/block/swim_asm.S
index 4913470b63e8..c8a89c0c4652 100644
--- a/drivers/block/swim_asm.S
+++ b/drivers/block/swim_asm.S
@@ -5,7 +5,7 @@
  * needs assembly language because is very timing dependent
  * this controller exists only on macintosh 680x0 based
  *
- * Copyright (C) 2004,2008 Laurent Vivier <Laurent@lvivier.info>
+ * Copyright (C) 2004, 2008 Laurent Vivier <Laurent@lvivier.info>
  *
  * based on Alastair Bridgewater SWIM analysis, 2001
  * based on netBSD IWM driver (c) 1997, 1998 Hauke Fath.
@@ -110,7 +110,6 @@ sector_data_mark:
 	/* read header */
 
 	moveq	#max_retry, %d2
-
 amark0:	tstb	%a2@
 	dbmi	%d2, amark0
 	bpl	signal_nonyb
@@ -118,7 +117,6 @@ amark0:	tstb	%a2@
 	moveb	%a5@, %a4@(o_track)
 
 	moveq	#max_retry, %d2
-
 amark1:	tstb	%a2@
 	dbmi	%d2, amark1
 	bpl	signal_nonyb
@@ -126,7 +124,6 @@ amark1:	tstb	%a2@
 	moveb	%a5@, %a4@(o_side)
 
 	moveq	#max_retry, %d2
-
 amark2:	tstb	%a2@
 	dbmi	%d2, amark2
 	bpl	signal_nonyb
@@ -134,7 +131,6 @@ amark2:	tstb	%a2@
 	moveb	%a5@, %a4@(o_sector)
 
 	moveq	#max_retry, %d2
-
 amark3:	tstb	%a2@
 	dbmi	%d2, amark3
 	bpl	signal_nonyb
@@ -142,7 +138,6 @@ amark3:	tstb	%a2@
 	moveb	%a5@, %a4@(o_size)
 
 	moveq	#max_retry, %d2
-
 crc0:	tstb	%a2@
 	dbmi	%d2, crc0
 	bpl	signal_nonyb
@@ -150,7 +145,6 @@ crc0:	tstb	%a2@
 	moveb	%a5@, %a4@(o_crc0)
 
 	moveq	#max_retry, %d2
-
 crc1:	moveb	%a2@, %d5
 	dbmi	%d2, crc1
 	bpl	signal_nonyb
@@ -197,13 +191,14 @@ mfm_read_data:
 
 	/* read data */
 
-	movel	#sector_size-1, %d4		/* sector size */
+	movel	#sector_size - 1, %d4		/* sector size */
 	movew	#max_retry, %d2
 read_data_loop:
 	moveb	%a2@, %d5
 	andb	#(.Lhr_fifo_1byte + .Lhr_fifo_2bytes), %d5
 	dbne	%d2, read_data_loop
 	beq	data_exit
+
 	moveq	#max_retry, %d2
 	moveb	%a5@, %d3
 	bsr	.Lmaybe_store
@@ -219,7 +214,6 @@ read_data_loop:
 
 	movew	#max_retry, %d2
 data_crc0:
-
 	tstb	%a2@
 	dbmi	%d2, data_crc0
 	bpl	data_exit
@@ -227,9 +221,7 @@ data_crc0:
 	moveb	%a5@, %d2
 
 	moveq	#max_retry, %d2
-
 data_crc1:
-
 	moveb	%a2@, %d5
 	dbmi	%d2, data_crc1
 	bpl	data_exit
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 30/32] swim: Define macros for constants
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (20 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 22/32] swim: Remove pointless mode0 register write Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 05/32] swim: Perform ISM/IWM mode switching according to specs Finn Thain
                   ` (9 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

Define a SEL_MASK macro to name the anonymous constant. Define STEPPING
rather than re-use STEP because the latter is a command bit macro (see also
GCR_MODE vs. SETGCR). No functional change, just better readability.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/block/swim.c b/drivers/block/swim.c
index 73d11e827e5d..69ac02b8b256 100644
--- a/drivers/block/swim.c
+++ b/drivers/block/swim.c
@@ -105,6 +105,8 @@ struct iwm {
 
 /* Select values for swim_select and swim_readbit */
 
+#define SEL_MASK	0x100
+
 #define SEEK_POSITIVE	0x000
 #define SEEK_NEGATIVE	0x004
 #define STEP		0x001
@@ -115,6 +117,7 @@ struct iwm {
 #define SETMFM		0x101
 #define SETGCR		0x105
 
+#define STEPPING	0x001
 #define READ_DATA_0	0x004
 #define ONEMEG_DRIVE	0x005
 #define SINGLE_SIDED	0x006
@@ -271,7 +274,7 @@ static inline void swim_select(struct swim __iomem *base, int sel)
 {
 	swim_write(base, phase, RELAX | PHASE_PIN_DIR);
 
-	via1_set_head(sel & 0x100);
+	via1_set_head(sel & SEL_MASK);
 
 	swim_write(base, phase, (sel & CA_MASK) | PHASE_PIN_DIR);
 }
@@ -366,7 +369,7 @@ static int swim_step(struct swim __iomem *base)
 {
 	swim_action(base, STEP);
 	udelay(150);
-	return swim_readbit_timeout(base, STEP, false, 20 * 1000);
+	return swim_readbit_timeout(base, STEPPING, false, 20 * 1000);
 }
 
 static int swim_track00(struct swim __iomem *base)
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 31/32] swim: Define symbols for constants
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (2 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 01/32] swim: Assert strobe with stable outputs Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 12/32] swim: Simplify return value initialization Finn Thain
                   ` (27 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

Define local symbols to give some meaning to anonymous constants.
No functional change.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim_asm.S | 24 ++++++++++++++----------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/drivers/block/swim_asm.S b/drivers/block/swim_asm.S
index c8a89c0c4652..c78efc30082a 100644
--- a/drivers/block/swim_asm.S
+++ b/drivers/block/swim_asm.S
@@ -43,6 +43,10 @@
 	.equ	sector_size, 512
 	.equ	.Lmark_sequence_len,	4
 
+	.equ	.Lmr_clear_fifo,	0x01
+	.equ	.Lmr_action,		0x08
+	.equ	.Lmr_write_action,	0x18
+
 	.equ	.Lhr_crc_error,		0x02
 	.equ	.Lhr_fifo_2bytes,	0x40
 	.equ	.Lhr_fifo_1byte,	0x80
@@ -95,11 +99,11 @@ sector_data_mark:
 	lea	%a3@(read_data), %a5
 	lea	%a3@(read_mark), %a3
 
-	moveb	#0x18, %a3@(write_mode0 - read_mark)
-	moveb	#0x01, %a3@(write_mode1 - read_mark)
-	moveb	#0x01, %a3@(write_mode0 - read_mark)
+	moveb	#.Lmr_write_action, %a3@(write_mode0 - read_mark)
+	moveb	#.Lmr_clear_fifo, %a3@(write_mode1 - read_mark)
+	moveb	#.Lmr_clear_fifo, %a3@(write_mode0 - read_mark)
 	tstb	%a3@(read_error - read_mark)
-	moveb	#0x08, %a3@(write_mode1 - read_mark)
+	moveb	#.Lmr_action, %a3@(write_mode1 - read_mark)
 
 	lea	sector_address_mark, %a1
 	moveq	#.Lmark_sequence_len, %d4
@@ -157,7 +161,7 @@ crc1:	moveb	%a2@, %d5
 
 	moveq	#0, %d0
 signal_nonyb:
-	moveb	#0x18, %a3@(write_mode0 - read_mark)
+	moveb	#.Lmr_write_action, %a3@(write_mode0 - read_mark)
 	rts
 
 	.global swim_read_sector_data
@@ -177,11 +181,11 @@ mfm_read_data:
 	lea	%a3@(read_data), %a5
 	lea	%a3@(read_mark), %a3
 
-	moveb	#0x18, %a3@(write_mode0 - read_mark)
-	moveb	#0x01, %a3@(write_mode1 - read_mark)
-	moveb	#0x01, %a3@(write_mode0 - read_mark)
+	moveb	#.Lmr_write_action, %a3@(write_mode0 - read_mark)
+	moveb	#.Lmr_clear_fifo, %a3@(write_mode1 - read_mark)
+	moveb	#.Lmr_clear_fifo, %a3@(write_mode0 - read_mark)
 	tstb	%a3@(read_error - read_mark)
-	moveb	#0x08, %a3@(write_mode1 - read_mark)
+	moveb	#.Lmr_action, %a3@(write_mode1 - read_mark)
 
 	lea	sector_data_mark, %a1
 	moveq	#.Lmark_sequence_len, %d4
@@ -239,7 +243,7 @@ data_crc1:
 	subl	%d4, %d0
 
 data_exit:
-	moveb	#0x18, %a3@(write_mode0 - read_mark)
+	moveb	#.Lmr_write_action, %a3@(write_mode0 - read_mark)
 	rts
 
 .Lmaybe_store:
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

* [PATCH v2 32/32] swim: Unexport global symbols
  2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
                   ` (11 preceding siblings ...)
  2026-08-17  1:17 ` [PATCH v2 28/32] swim: Remove unused macro definitions Finn Thain
@ 2026-08-17  1:17 ` Finn Thain
  2026-08-17  1:17 ` [PATCH v2 24/32] swim: Don't search beyond the first data mark Finn Thain
                   ` (18 subsequent siblings)
  31 siblings, 0 replies; 33+ messages in thread
From: Finn Thain @ 2026-08-17  1:17 UTC (permalink / raw)
  To: Jens Axboe, Laurent Vivier
  Cc: Geert Uytterhoeven, Joshua Thompson, linux-block, linux-m68k,
	linux-kernel

These symbols aren't used outside of this file so use local ones.
No functional change.

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Signed-off-by: Finn Thain <fthain@linux-m68k.org>
---
 drivers/block/swim_asm.S | 218 ++++++++++++++++++++-------------------
 1 file changed, 112 insertions(+), 106 deletions(-)

diff --git a/drivers/block/swim_asm.S b/drivers/block/swim_asm.S
index c78efc30082a..c3f1476948b5 100644
--- a/drivers/block/swim_asm.S
+++ b/drivers/block/swim_asm.S
@@ -14,33 +14,33 @@
  * 2008-11-05 (lv) - add get_swim_mode
  */
 
-	.equ	write_data,	0x0000
-	.equ	write_mark,	0x0200
-	.equ	write_CRC,	0x0400
-	.equ	write_parameter,0x0600
-	.equ	write_phase,	0x0800
-	.equ	write_setup,	0x0a00
-	.equ	write_mode0,	0x0c00
-	.equ	write_mode1,	0x0e00
-	.equ	read_data,	0x1000
-	.equ	read_mark,	0x1200
-	.equ	read_error,	0x1400
-	.equ	read_parameter,	0x1600
-	.equ	read_phase,	0x1800
-	.equ	read_setup,	0x1a00
-	.equ	read_status,	0x1c00
-	.equ	read_handshake,	0x1e00
-
-	.equ	o_side, 0
-	.equ	o_track, 1
-	.equ	o_sector, 2
-	.equ	o_size, 3
-	.equ	o_crc0, 4
-	.equ	o_crc1, 5
-
-	.equ	seek_time, 30000
-	.equ	max_retry, 40
-	.equ	sector_size, 512
+	.equ	.Lwrite_data,		0x0000
+	.equ	.Lwrite_mark,		0x0200
+	.equ	.Lwrite_CRC,		0x0400
+	.equ	.Lwrite_parameter,	0x0600
+	.equ	.Lwrite_phase,		0x0800
+	.equ	.Lwrite_setup,		0x0a00
+	.equ	.Lwrite_mode0,		0x0c00
+	.equ	.Lwrite_mode1,		0x0e00
+	.equ	.Lread_data,		0x1000
+	.equ	.Lread_mark,		0x1200
+	.equ	.Lread_error,		0x1400
+	.equ	.Lread_parameter,	0x1600
+	.equ	.Lread_phase,		0x1800
+	.equ	.Lread_setup,		0x1a00
+	.equ	.Lread_status,		0x1c00
+	.equ	.Lread_handshake,	0x1e00
+
+	.equ	.Lo_side,		0
+	.equ	.Lo_track,		1
+	.equ	.Lo_sector,		2
+	.equ	.Lo_size,		3
+	.equ	.Lo_crc0,		4
+	.equ	.Lo_crc1,		5
+
+	.equ	.Lseek_time,		30000
+	.equ	.Lmax_retry,		40
+	.equ	.Lsector_size,		512
 	.equ	.Lmark_sequence_len,	4
 
 	.equ	.Lmr_clear_fifo,	0x01
@@ -63,7 +63,7 @@
 
 	moveq	#-1, %d1
 	subq	#1, %d4
-	movew	#seek_time, %d2
+	movew	#.Lseek_time, %d2
 
 5:	tstb	%a2@
 	dbmi	%d2, 5b
@@ -88,80 +88,86 @@ swim_read_sector_header:
 	unlk	%a6
 	rts
 
-sector_address_mark:
+.Lsector_address_mark:
 	.byte	0xa1, 0xa1, 0xa1, 0xfe
-sector_data_mark:
+.Lsector_data_mark:
 	.byte	0xa1, 0xa1, 0xa1, 0xfb
 
 .Lmfm_read_header:
 	movel	%a6@(0x08), %a3
-	lea	%a3@(read_handshake), %a2
-	lea	%a3@(read_data), %a5
-	lea	%a3@(read_mark), %a3
+	lea	%a3@(.Lread_handshake), %a2
+	lea	%a3@(.Lread_data), %a5
+	lea	%a3@(.Lread_mark), %a3
 
-	moveb	#.Lmr_write_action, %a3@(write_mode0 - read_mark)
-	moveb	#.Lmr_clear_fifo, %a3@(write_mode1 - read_mark)
-	moveb	#.Lmr_clear_fifo, %a3@(write_mode0 - read_mark)
-	tstb	%a3@(read_error - read_mark)
-	moveb	#.Lmr_action, %a3@(write_mode1 - read_mark)
+	moveb	#.Lmr_write_action, %a3@(.Lwrite_mode0 - .Lread_mark)
+	moveb	#.Lmr_clear_fifo, %a3@(.Lwrite_mode1 - .Lread_mark)
+	moveb	#.Lmr_clear_fifo, %a3@(.Lwrite_mode0 - .Lread_mark)
+	tstb	%a3@(.Lread_error - .Lread_mark)
+	moveb	#.Lmr_action, %a3@(.Lwrite_mode1 - .Lread_mark)
 
-	lea	sector_address_mark, %a1
+	lea	.Lsector_address_mark, %a1
 	moveq	#.Lmark_sequence_len, %d4
 	bsr	.Lmfm_mark_check
 	tstl	%d1
-	bne	signal_nonyb
+	bne	.Lsignal_nonyb
 
 	/* read header */
 
-	moveq	#max_retry, %d2
-amark0:	tstb	%a2@
-	dbmi	%d2, amark0
-	bpl	signal_nonyb
+	moveq	#.Lmax_retry, %d2
+.Lamark0:
+	tstb	%a2@
+	dbmi	%d2, .Lamark0
+	bpl	.Lsignal_nonyb
 
-	moveb	%a5@, %a4@(o_track)
+	moveb	%a5@, %a4@(.Lo_track)
 
-	moveq	#max_retry, %d2
-amark1:	tstb	%a2@
-	dbmi	%d2, amark1
-	bpl	signal_nonyb
+	moveq	#.Lmax_retry, %d2
+.Lamark1:
+	tstb	%a2@
+	dbmi	%d2, .Lamark1
+	bpl	.Lsignal_nonyb
 
-	moveb	%a5@, %a4@(o_side)
+	moveb	%a5@, %a4@(.Lo_side)
 
-	moveq	#max_retry, %d2
-amark2:	tstb	%a2@
-	dbmi	%d2, amark2
-	bpl	signal_nonyb
+	moveq	#.Lmax_retry, %d2
+.Lamark2:
+	tstb	%a2@
+	dbmi	%d2, .Lamark2
+	bpl	.Lsignal_nonyb
 
-	moveb	%a5@, %a4@(o_sector)
+	moveb	%a5@, %a4@(.Lo_sector)
 
-	moveq	#max_retry, %d2
-amark3:	tstb	%a2@
-	dbmi	%d2, amark3
-	bpl	signal_nonyb
+	moveq	#.Lmax_retry, %d2
+.Lamark3:
+	tstb	%a2@
+	dbmi	%d2, .Lamark3
+	bpl	.Lsignal_nonyb
 
-	moveb	%a5@, %a4@(o_size)
+	moveb	%a5@, %a4@(.Lo_size)
 
-	moveq	#max_retry, %d2
-crc0:	tstb	%a2@
-	dbmi	%d2, crc0
-	bpl	signal_nonyb
+	moveq	#.Lmax_retry, %d2
+.Lcrc0:
+	tstb	%a2@
+	dbmi	%d2, .Lcrc0
+	bpl	.Lsignal_nonyb
 
-	moveb	%a5@, %a4@(o_crc0)
+	moveb	%a5@, %a4@(.Lo_crc0)
 
-	moveq	#max_retry, %d2
-crc1:	moveb	%a2@, %d5
-	dbmi	%d2, crc1
-	bpl	signal_nonyb
+	moveq	#.Lmax_retry, %d2
+.Lcrc1:
+	moveb	%a2@, %d5
+	dbmi	%d2, .Lcrc1
+	bpl	.Lsignal_nonyb
 
-	moveb	%a5@, %a4@(o_crc1)
+	moveb	%a5@, %a4@(.Lo_crc1)
 
 	moveb	%a2@, %d5
 	andb	#.Lhr_crc_error, %d5
-	bne	signal_nonyb
+	bne	.Lsignal_nonyb
 
 	moveq	#0, %d0
-signal_nonyb:
-	moveb	#.Lmr_write_action, %a3@(write_mode0 - read_mark)
+.Lsignal_nonyb:
+	moveb	#.Lmr_write_action, %a3@(.Lwrite_mode0 - .Lread_mark)
 	rts
 
 	.global swim_read_sector_data
@@ -170,80 +176,80 @@ swim_read_sector_data:
 	moveml	%d1-%d5/%a0-%a5,%sp@-
 	movel	%a6@(0x0c), %a4
 	moveq	#-1, %d0
-	bsr	mfm_read_data
+	bsr	.Lmfm_read_data
 	moveml	%sp@+, %d1-%d5/%a0-%a5
 	unlk	%a6
 	rts
 
-mfm_read_data:
+.Lmfm_read_data:
 	movel	%a6@(0x08), %a3
-	lea	%a3@(read_handshake), %a2
-	lea	%a3@(read_data), %a5
-	lea	%a3@(read_mark), %a3
+	lea	%a3@(.Lread_handshake), %a2
+	lea	%a3@(.Lread_data), %a5
+	lea	%a3@(.Lread_mark), %a3
 
-	moveb	#.Lmr_write_action, %a3@(write_mode0 - read_mark)
-	moveb	#.Lmr_clear_fifo, %a3@(write_mode1 - read_mark)
-	moveb	#.Lmr_clear_fifo, %a3@(write_mode0 - read_mark)
-	tstb	%a3@(read_error - read_mark)
-	moveb	#.Lmr_action, %a3@(write_mode1 - read_mark)
+	moveb	#.Lmr_write_action, %a3@(.Lwrite_mode0 - .Lread_mark)
+	moveb	#.Lmr_clear_fifo, %a3@(.Lwrite_mode1 - .Lread_mark)
+	moveb	#.Lmr_clear_fifo, %a3@(.Lwrite_mode0 - .Lread_mark)
+	tstb	%a3@(.Lread_error - .Lread_mark)
+	moveb	#.Lmr_action, %a3@(.Lwrite_mode1 - .Lread_mark)
 
-	lea	sector_data_mark, %a1
+	lea	.Lsector_data_mark, %a1
 	moveq	#.Lmark_sequence_len, %d4
 	bsr	.Lmfm_mark_check
 	tstl	%d1
-	bne	data_exit
+	bne	.Ldata_exit
 
 	/* read data */
 
-	movel	#sector_size - 1, %d4		/* sector size */
-	movew	#max_retry, %d2
-read_data_loop:
+	movel	#.Lsector_size - 1, %d4		/* sector size */
+	movew	#.Lmax_retry, %d2
+.Lread_data_loop:
 	moveb	%a2@, %d5
 	andb	#(.Lhr_fifo_1byte + .Lhr_fifo_2bytes), %d5
-	dbne	%d2, read_data_loop
-	beq	data_exit
+	dbne	%d2, .Lread_data_loop
+	beq	.Ldata_exit
 
-	moveq	#max_retry, %d2
+	moveq	#.Lmax_retry, %d2
 	moveb	%a5@, %d3
 	bsr	.Lmaybe_store
 	dbra	%d4, 1f
-	bra	data_crc0
+	bra	.Ldata_crc0
 1:	andb	#.Lhr_fifo_2bytes, %d5
-	beq	read_data_loop
+	beq	.Lread_data_loop
 	moveb	%a5@, %d3
 	bsr	.Lmaybe_store
-	dbra	%d4, read_data_loop
+	dbra	%d4, .Lread_data_loop
 
 	/* read CRC */
 
-	movew	#max_retry, %d2
-data_crc0:
+	movew	#.Lmax_retry, %d2
+.Ldata_crc0:
 	tstb	%a2@
-	dbmi	%d2, data_crc0
-	bpl	data_exit
+	dbmi	%d2, .Ldata_crc0
+	bpl	.Ldata_exit
 
 	moveb	%a5@, %d2
 
-	moveq	#max_retry, %d2
-data_crc1:
+	moveq	#.Lmax_retry, %d2
+.Ldata_crc1:
 	moveb	%a2@, %d5
-	dbmi	%d2, data_crc1
-	bpl	data_exit
+	dbmi	%d2, .Ldata_crc1
+	bpl	.Ldata_exit
 
 	moveb	%a5@, %d2
 
 	moveb	%a2@, %d5
 	andb	#.Lhr_crc_error, %d5
-	bne	data_exit
+	bne	.Ldata_exit
 
 	/* return number of bytes read */
 
-	movel	#sector_size, %d0
+	movel	#.Lsector_size, %d0
 	addw	#1, %d4
 	subl	%d4, %d0
 
-data_exit:
-	moveb	#.Lmr_write_action, %a3@(write_mode0 - read_mark)
+.Ldata_exit:
+	moveb	#.Lmr_write_action, %a3@(.Lwrite_mode0 - .Lread_mark)
 	rts
 
 .Lmaybe_store:
-- 
2.52.0


^ permalink raw reply related	[flat|nested] 33+ messages in thread

end of thread, other threads:[~2026-08-17  1:59 UTC | newest]

Thread overview: 33+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-17  1:17 [PATCH v2 00/32] block/swim: Fixes and improvements Finn Thain
2026-08-17  1:17 ` [PATCH v2 26/32] swim: Move swd initialization Finn Thain
2026-08-17  1:17 ` [PATCH v2 23/32] swim: Don't needlessly re-read sectors Finn Thain
2026-08-17  1:17 ` [PATCH v2 01/32] swim: Assert strobe with stable outputs Finn Thain
2026-08-17  1:17 ` [PATCH v2 31/32] swim: Define symbols for constants Finn Thain
2026-08-17  1:17 ` [PATCH v2 12/32] swim: Simplify return value initialization Finn Thain
2026-08-17  1:17 ` [PATCH v2 20/32] swim: Check drive ready bit Finn Thain
2026-08-17  1:17 ` [PATCH v2 16/32] swim: Fix buffer overflow Finn Thain
2026-08-17  1:17 ` [PATCH v2 27/32] swim: Add some helpful references Finn Thain
2026-08-17  1:17 ` [PATCH v2 19/32] swim: Deduplicate polling loops Finn Thain
2026-08-17  1:17 ` [PATCH v2 04/32] swim: Don't disable drive after every sector Finn Thain
2026-08-17  1:17 ` [PATCH v2 11/32] swim: Handle FIFO timeout error Finn Thain
2026-08-17  1:17 ` [PATCH v2 28/32] swim: Remove unused macro definitions Finn Thain
2026-08-17  1:17 ` [PATCH v2 32/32] swim: Unexport global symbols Finn Thain
2026-08-17  1:17 ` [PATCH v2 24/32] swim: Don't search beyond the first data mark Finn Thain
2026-08-17  1:17 ` [PATCH v2 03/32] swim: Enable the drive when probing Finn Thain
2026-08-17  1:17 ` [PATCH v2 13/32] swim: Check for CRC errors Finn Thain
2026-08-17  1:17 ` [PATCH v2 25/32] swim: Remove pointless specifiers Finn Thain
2026-08-17  1:17 ` [PATCH v2 08/32] swim: Don't start motor until medium is present Finn Thain
2026-08-17  1:17 ` [PATCH v2 02/32] swim: Select appropriate drive once only Finn Thain
2026-08-17  1:17 ` [PATCH v2 15/32] swim: Don't use the mark register to read data Finn Thain
2026-08-17  1:17 ` [PATCH v2 22/32] swim: Remove pointless mode0 register write Finn Thain
2026-08-17  1:17 ` [PATCH v2 30/32] swim: Define macros for constants Finn Thain
2026-08-17  1:17 ` [PATCH v2 05/32] swim: Perform ISM/IWM mode switching according to specs Finn Thain
2026-08-17  1:17 ` [PATCH v2 18/32] swim: Remove redundant RELAX actions Finn Thain
2026-08-17  1:17 ` [PATCH v2 29/32] swim: Clean up whitespace Finn Thain
2026-08-17  1:17 ` [PATCH v2 14/32] swim: Check error register during sector read Finn Thain
2026-08-17  1:17 ` [PATCH v2 21/32] swim: Revisit delays Finn Thain
2026-08-17  1:17 ` [PATCH v2 10/32] swim: Add track zero recalibration delay Finn Thain
2026-08-17  1:17 ` [PATCH v2 17/32] swim: Convert to blocking queue Finn Thain
2026-08-17  1:17 ` [PATCH v2 06/32] swim: Configure parameter memory Finn Thain
2026-08-17  1:17 ` [PATCH v2 09/32] swim: Recalibrate when drive is probed Finn Thain
2026-08-17  1:17 ` [PATCH v2 07/32] swim: Enable clock divider only where appropriate Finn Thain

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox