public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
To: Mikael Pettersson <mikpe@csd.uu.se>
Cc: S.Breedveld@ewi.tudelft.nl,
	Linux Kernel list <linux-kernel@vger.kernel.org>
Subject: Re: PowerMac floppy (SWIM-3) doesn't compile
Date: Mon, 01 Dec 2003 11:11:20 +1100	[thread overview]
Message-ID: <1070237480.683.80.camel@gaston> (raw)
In-Reply-To: <200311301125.hAUBPRC4029084@harpo.it.uu.se>

On Sun, 2003-11-30 at 22:25, Mikael Pettersson wrote:
> On Sun, 30 Nov 2003 10:19:07 +0100 (MET), Sebastiaan <S.Breedveld@ewi.tudelft.nl> wrote:
> >I am trying to build the 2.6.0-test11 kernel for my PowerMac 7300/166, but
> >the floppy controller doesn't want to compile. I have:
> 
> Known problem. Has been reported several times, but the PPC
> maintainers haven't bothered merging the fix yet.

The maintainer did bother, but along with a bunch of other PPC
driver updates, the fix is on hold until after 2.6.0. Code
freeze...

Also, the swim3 drivers, even with that fix, isn't in a very
good shape. It needs to be cleaned up and ported to the new
driver model.

> I'm using the patch below since the 2.5.7x kernels.
> (Paul Mackerras' 2.4 swim3 rework forward-ported to 2.5 by me.)
> There's also an "official" powermac tree somewhere which
> includes some swim3 patch, but I don't know if it's the same
> as this one.

Please test and let me know. It's at
bk://ppc.bkbits.net/linuxppc-2.5-benh or rsync from
source.mvista.com::linuxppc-2.5-benh.

> As for the boot problem you reported, please try a newer gcc
> like 3.2.3 or 3.3.2. I had lots of wierd problems with 2.95.3
> and the 2.4 kernels on ppc before I switched to gcc-3.x.x.
> 
> 2.6.0-test11 works just fine on my PM4400.
> 
> /Mikael
> 
> diff -ruN linux-2.6.0-test11/drivers/block/swim3.c linux-2.6.0-test11.swim3-fixes/drivers/block/swim3.c
> --- linux-2.6.0-test11/drivers/block/swim3.c	2003-08-09 11:54:06.000000000 +0200
> +++ linux-2.6.0-test11.swim3-fixes/drivers/block/swim3.c	2003-11-26 23:50:36.000000000 +0100
> @@ -24,7 +24,10 @@
>  #include <linux/delay.h>
>  #include <linux/fd.h>
>  #include <linux/ioctl.h>
> +#include <linux/blkdev.h>
>  #include <linux/devfs_fs_kernel.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
>  #include <asm/io.h>
>  #include <asm/dbdma.h>
>  #include <asm/prom.h>
> @@ -144,7 +147,7 @@
>  #define RELAX		3	/* also eject in progress */
>  #define READ_DATA_0	4
>  #define TWOMEG_DRIVE	5
> -#define SINGLE_SIDED	6
> +#define SINGLE_SIDED	6	/* drive or diskette is 4MB type? */
>  #define DRIVE_PRESENT	7
>  #define DISK_IN		8
>  #define WRITE_PROT	9
> @@ -184,6 +187,7 @@
>  	int	req_sector;	/* sector number ditto */
>  	int	scount;		/* # sectors we're transferring at present */
>  	int	retries;
> +	int	settle_time;
>  	int	secpercyl;	/* disk geometry information */
>  	int	secpertrack;
>  	int	total_secs;
> @@ -232,8 +236,9 @@
>  static void act(struct floppy_state *fs);
>  static void scan_timeout(unsigned long data);
>  static void seek_timeout(unsigned long data);
> +static void settle_timeout(unsigned long data);
>  static void xfer_timeout(unsigned long data);
> -static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
> +static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
>  /*static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);*/
>  static int grab_drive(struct floppy_state *fs, enum swim_state state,
>  		      int interruptible);
> @@ -274,7 +279,6 @@
>  	udelay(2);
>  	out_8(&sw->select, sw->select & ~LSTRB);
>  	udelay(1);
> -	out_8(&sw->select, RELAX);
>  }
>  
>  static int swim3_readbit(struct floppy_state *fs, int bit)
> @@ -283,9 +287,8 @@
>  	int stat;
>  
>  	swim3_select(fs, bit);
> -	udelay(10);
> +	udelay(1);
>  	stat = in_8(&sw->status);
> -	out_8(&sw->select, RELAX);
>  	return (stat & DATA) == 0;
>  }
>  
> @@ -374,13 +377,13 @@
>  static inline void scan_track(struct floppy_state *fs)
>  {
>  	volatile struct swim3 *sw = fs->swim3;
> -	int xx;
>  
>  	swim3_select(fs, READ_DATA_0);
> -	xx = sw->intr;		/* clear SEEN_SECTOR bit */
> +	in_8(&sw->intr);		/* clear SEEN_SECTOR bit */
> +	in_8(&sw->error);
> +	out_8(&sw->intr_enable, SEEN_SECTOR);
>  	out_8(&sw->control_bis, DO_ACTION);
>  	/* enable intr when track found */
> -	out_8(&sw->intr_enable, ERROR_INTR | SEEN_SECTOR);
>  	set_timeout(fs, HZ, scan_timeout);	/* enable timeout */
>  }
>  
> @@ -395,12 +398,14 @@
>  		swim3_action(fs, SEEK_NEGATIVE);
>  		sw->nseek = -n;
>  	}
> -	fs->expect_cyl = (fs->cur_cyl > 0)? fs->cur_cyl + n: -1;
> +	fs->expect_cyl = (fs->cur_cyl >= 0)? fs->cur_cyl + n: -1;
>  	swim3_select(fs, STEP);
> -	out_8(&sw->control_bis, DO_SEEK);
> +	in_8(&sw->error);
>  	/* enable intr when seek finished */
> -	out_8(&sw->intr_enable, ERROR_INTR | SEEK_DONE);
> -	set_timeout(fs, HZ/2, seek_timeout);	/* enable timeout */
> +	out_8(&sw->intr_enable, SEEK_DONE);
> +	out_8(&sw->control_bis, DO_SEEK);
> +	set_timeout(fs, 3*HZ, seek_timeout);	/* enable timeout */
> +	fs->settle_time = 0;
>  }
>  
>  static inline void init_dma(struct dbdma_cmd *cp, int cmd,
> @@ -448,18 +453,21 @@
>  	}
>  	++cp;
>  	out_le16(&cp->command, DBDMA_STOP);
> +	out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
> +	in_8(&sw->error);
> +	out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
> +	if (rq_data_dir(fd_req) == WRITE)
> +		out_8(&sw->control_bis, WRITE_SECTORS);
> +	in_8(&sw->intr);
>  	out_le32(&dr->control, (RUN << 16) | RUN);
> -	out_8(&sw->control_bis,
> -	      (rq_data_dir(fd_req) == WRITE? WRITE_SECTORS: 0) | DO_ACTION);
>  	/* enable intr when transfer complete */
> -	out_8(&sw->intr_enable, ERROR_INTR | TRANSFER_DONE);
> +	out_8(&sw->intr_enable, TRANSFER_DONE);
> +	out_8(&sw->control_bis, DO_ACTION);
>  	set_timeout(fs, 2*HZ, xfer_timeout);	/* enable timeout */
>  }
>  
>  static void act(struct floppy_state *fs)
>  {
> -	volatile struct swim3 *sw = fs->swim3;
> -
>  	for (;;) {
>  		switch (fs->state) {
>  		case idle:
> @@ -492,20 +500,10 @@
>  			return;
>  
>  		case settling:
> -			/* wait for SEEK_COMPLETE to become true */
> -			swim3_select(fs, SEEK_COMPLETE);
> -			udelay(10);
> -			out_8(&sw->intr_enable, ERROR_INTR | DATA_CHANGED);
> -			in_8(&sw->intr);	/* clear DATA_CHANGED */
> -			if (in_8(&sw->status) & DATA) {
> -				/* seek_complete is not yet true */
> -				set_timeout(fs, HZ/2, seek_timeout);
> -				return;
> -			}
> -			out_8(&sw->intr_enable, 0);
> -			in_8(&sw->intr);
> -			fs->state = locating;
> -			break;
> +			/* check for SEEK_COMPLETE after 30ms */
> +			fs->settle_time = (HZ + 32) / 33;
> +			set_timeout(fs, fs->settle_time, settle_timeout);
> +			return;
>  
>  		case do_transfer:
>  			if (fs->cur_cyl != fs->req_cyl) {
> @@ -537,7 +535,7 @@
>  	volatile struct swim3 *sw = fs->swim3;
>  
>  	fs->timeout_pending = 0;
> -	out_8(&sw->control_bic, DO_ACTION);
> +	out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
>  	out_8(&sw->select, RELAX);
>  	out_8(&sw->intr_enable, 0);
>  	fs->cur_cyl = -1;
> @@ -557,20 +555,34 @@
>  	volatile struct swim3 *sw = fs->swim3;
>  
>  	fs->timeout_pending = 0;
> -	if (fs->state == settling) {
> -		printk(KERN_ERR "swim3: MSI sel=%x ctrl=%x stat=%x intr=%x ie=%x\n",
> -		       sw->select, sw->control, sw->status, sw->intr, sw->intr_enable);
> -	}
>  	out_8(&sw->control_bic, DO_SEEK);
>  	out_8(&sw->select, RELAX);
>  	out_8(&sw->intr_enable, 0);
> -	if (fs->state == settling && swim3_readbit(fs, SEEK_COMPLETE)) {
> -		/* printk(KERN_DEBUG "swim3: missed settling interrupt\n"); */
> +	printk(KERN_ERR "swim3: seek timeout\n");
> +	end_request(fd_req, 0);
> +	fs->state = idle;
> +	start_request(fs);
> +}
> +
> +static void settle_timeout(unsigned long data)
> +{
> +	struct floppy_state *fs = (struct floppy_state *) data;
> +	volatile struct swim3 *sw = fs->swim3;
> +
> +	fs->timeout_pending = 0;
> +	if (swim3_readbit(fs, SEEK_COMPLETE)) {
> +		out_8(&sw->select, RELAX);
>  		fs->state = locating;
>  		act(fs);
>  		return;
>  	}
> -	printk(KERN_ERR "swim3: seek timeout\n");
> +	out_8(&sw->select, RELAX);
> +	if (fs->settle_time < 2*HZ) {
> +		++fs->settle_time;
> +		set_timeout(fs, 1, settle_timeout);
> +		return;
> +	}
> +	printk(KERN_ERR "swim3: seek settle timeout\n");
>  	end_request(fd_req, 0);
>  	fs->state = idle;
>  	start_request(fs);
> @@ -583,9 +595,13 @@
>  	struct dbdma_regs *dr = fs->dma;
>  	struct dbdma_cmd *cp = fs->dma_cmd;
>  	unsigned long s;
> +	int n;
>  
>  	fs->timeout_pending = 0;
>  	st_le32(&dr->control, RUN << 16);
> +	/* We must wait a bit for dbdma to stop */
> +	for (n = 0; (in_le32(&dr->status) & ACTIVE) && n < 1000; n++)
> +		udelay(1);
>  	out_8(&sw->intr_enable, 0);
>  	out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION);
>  	out_8(&sw->select, RELAX);
> @@ -604,7 +620,7 @@
>  	start_request(fs);
>  }
>  
> -static void swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
> +static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
>  {
>  	struct floppy_state *fs = (struct floppy_state *) dev_id;
>  	volatile struct swim3 *sw = fs->swim3;
> @@ -613,18 +629,15 @@
>  	struct dbdma_regs *dr;
>  	struct dbdma_cmd *cp;
>  
> -	err = in_8(&sw->error);
>  	intr = in_8(&sw->intr);
> -#if 0
> -	printk("swim3 intr state=%d intr=%x err=%x\n", fs->state, intr, err);
> -#endif
> +	err = (intr & ERROR_INTR)? in_8(&sw->error): 0;
>  	if ((intr & ERROR_INTR) && fs->state != do_transfer)
>  		printk(KERN_ERR "swim3_interrupt, state=%d, dir=%lx, intr=%x, err=%x\n",
>  		       fs->state, rq_data_dir(fd_req), intr, err);
>  	switch (fs->state) {
>  	case locating:
>  		if (intr & SEEN_SECTOR) {
> -			out_8(&sw->control_bic, DO_ACTION);
> +			out_8(&sw->control_bic, DO_ACTION | WRITE_SECTORS);
>  			out_8(&sw->select, RELAX);
>  			out_8(&sw->intr_enable, 0);
>  			del_timer(&fs->timeout);
> @@ -674,19 +687,33 @@
>  	case do_transfer:
>  		if ((intr & (ERROR_INTR | TRANSFER_DONE)) == 0)
>  			break;
> -		dr = fs->dma;
> -		cp = fs->dma_cmd;
> -		/* We must wait a bit for dbdma to complete */
> -		for (n=0; (in_le32(&dr->status) & ACTIVE) && n < 1000; n++)
> -			udelay(10);
> -		DBDMA_DO_STOP(dr);
>  		out_8(&sw->intr_enable, 0);
>  		out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION);
>  		out_8(&sw->select, RELAX);
>  		del_timer(&fs->timeout);
>  		fs->timeout_pending = 0;
> +		dr = fs->dma;
> +		cp = fs->dma_cmd;
>  		if (rq_data_dir(fd_req) == WRITE)
>  			++cp;
> +		/*
> +		 * Check that the main data transfer has finished.
> +		 * On writing, the swim3 sometimes doesn't use
> +		 * up all the bytes of the postamble, so we can still
> +		 * see DMA active here.  That doesn't matter as long
> +		 * as all the sector data has been transferred.
> +		 */
> +		if ((intr & ERROR_INTR) == 0 && cp->xfer_status == 0) {
> +			/* wait a little while for DMA to complete */
> +			for (n = 0; n < 100; ++n) {
> +				if (cp->xfer_status != 0)
> +					break;
> +				udelay(1);
> +				barrier();
> +			}
> +		}
> +		/* turn off DMA */
> +		out_le32(&dr->control, (RUN | PAUSE) << 16);
>  		stat = ld_le16(&cp->xfer_status);
>  		resid = ld_le16(&cp->res_count);
>  		if (intr & ERROR_INTR) {
> @@ -742,6 +769,7 @@
>  	default:
>  		printk(KERN_ERR "swim3: don't know what to do in state %d\n", fs->state);
>  	}
> +	return IRQ_HANDLED;
>  }
>  
>  /*
> @@ -793,16 +821,19 @@
>  	if (err)
>  		return err;
>  	swim3_action(fs, EJECT);
> -	for (n = 2*HZ; n > 0; --n) {
> -		if (swim3_readbit(fs, RELAX))
> -			break;
> +	for (n = 20; n > 0; --n) {
>  		if (signal_pending(current)) {
>  			err = -EINTR;
>  			break;
>  		}
> +		swim3_select(fs, RELAX);
>  		current->state = TASK_INTERRUPTIBLE;
>  		schedule_timeout(1);
> +		if (swim3_readbit(fs, DISK_IN) == 0)
> +			break;
>  	}
> +	swim3_select(fs, RELAX);
> +	udelay(150);
>  	fs->ejected = 1;
>  	release_drive(fs);
>  	return err;
> @@ -847,29 +878,31 @@
>  	if (fs->ref_count == 0) {
>  		if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
>  			return -ENXIO;
> -		out_8(&sw->mode, 0x95);
> -		out_8(&sw->control_bic, 0xff);
>  		out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
> +		out_8(&sw->control_bic, 0xff);
> +		out_8(&sw->mode, 0x95);
>  		udelay(10);
>  		out_8(&sw->intr_enable, 0);
>  		out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
>  		swim3_action(fs, MOTOR_ON);
>  		fs->write_prot = -1;
>  		fs->cur_cyl = -1;
> -		for (n = HZ; n > 0; --n) {
> -			if (swim3_readbit(fs, SEEK_COMPLETE))
> +		for (n = 0; n < 2 * HZ; ++n) {
> +			if (n >= HZ/30 && swim3_readbit(fs, SEEK_COMPLETE))
>  				break;
>  			if (signal_pending(current)) {
>  				err = -EINTR;
>  				break;
>  			}
> +			swim3_select(fs, RELAX);
>  			current->state = TASK_INTERRUPTIBLE;
>  			schedule_timeout(1);
>  		}
>  		if (err == 0 && (swim3_readbit(fs, SEEK_COMPLETE) == 0
>  				 || swim3_readbit(fs, DISK_IN) == 0))
>  			err = -ENXIO;
> -		swim3_action(fs, 9);
> +		swim3_action(fs, SETMFM);
> +		swim3_select(fs, RELAX);
>  
>  	} else if (fs->ref_count == -1 || filp->f_flags & O_EXCL)
>  		return -EBUSY;
> @@ -892,6 +925,7 @@
>  		if (fs->ref_count == 0) {
>  			swim3_action(fs, MOTOR_OFF);
>  			out_8(&sw->control_bic, DRIVE_ENABLE | INTR_ENABLE);
> +			swim3_select(fs, RELAX);
>  		}
>  		return err;
>  	}
> @@ -911,6 +945,7 @@
>  	if (fs->ref_count > 0 && --fs->ref_count == 0) {
>  		swim3_action(fs, MOTOR_OFF);
>  		out_8(&sw->control_bic, 0xff);
> +		swim3_select(fs, RELAX);
>  	}
>  	return 0;
>  }
> @@ -933,15 +968,17 @@
>  	sw = fs->swim3;
>  	grab_drive(fs, revalidating, 0);
>  	out_8(&sw->intr_enable, 0);
> -	out_8(&sw->control_bis, DRIVE_ENABLE | INTR_ENABLE);
> -	swim3_action(fs, MOTOR_ON);
> +	out_8(&sw->control_bis, DRIVE_ENABLE);
> +	swim3_action(fs, MOTOR_ON);	/* necessary? */
>  	fs->write_prot = -1;
>  	fs->cur_cyl = -1;
> +	mdelay(1);
>  	for (n = HZ; n > 0; --n) {
>  		if (swim3_readbit(fs, SEEK_COMPLETE))
>  			break;
>  		if (signal_pending(current))
>  			break;
> +		swim3_select(fs, RELAX);
>  		current->state = TASK_INTERRUPTIBLE;
>  		schedule_timeout(1);
>  	}
> @@ -951,17 +988,14 @@
>  		swim3_action(fs, MOTOR_OFF);
>  	else {
>  		fs->ejected = 0;
> -		swim3_action(fs, 9);
> +		swim3_action(fs, SETMFM);
>  	}
> +	swim3_select(fs, RELAX);
>  
>  	release_drive(fs);
>  	return ret;
>  }
>  
> -static void floppy_off(unsigned int nr)
> -{
> -}
> -
>  static struct block_device_operations floppy_fops = {
>  	.open		= floppy_open,
>  	.release	= floppy_release,
> @@ -1104,3 +1138,5 @@
>  	
>  	return 0;
>  }
> +
> +module_init(swim3_init)
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
-- 
Benjamin Herrenschmidt <benh@kernel.crashing.org>


  parent reply	other threads:[~2003-12-01  0:12 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-11-30 11:25 PowerMac floppy (SWIM-3) doesn't compile Mikael Pettersson
2003-11-30 13:35 ` Sebastiaan
2003-12-01  0:11 ` Benjamin Herrenschmidt [this message]
  -- strict thread matches above, loose matches on Subject: below --
2003-11-30  9:19 Sebastiaan

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1070237480.683.80.camel@gaston \
    --to=benh@kernel.crashing.org \
    --cc=S.Breedveld@ewi.tudelft.nl \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mikpe@csd.uu.se \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox