linux IDE驱动分析之Ide_driver的注册(三)

Ide_driver的注册(三)

Linux内核代码之所以如此精辟,我觉得很主要的一个原因是容易让人产生健忘,这样前面说的后面联系不上,猛然回头一看的时候,很容易让人产生扑朔迷离的感觉,从而衬托出他的一种境界。当然,要说清楚这里的这个故事就得回到N年以前我们讲到的一个传说。早在ide-genericadd-host的时候我们通过层层调用最终通过request_irq申请了一个ide中断,当说到对应的中断向量是ide_intr的时候我们妥协了,说以后有用到的时候再来分析。今天总算到了他开花结果的时候了,进去开开眼界:

[ide-io.c]

753 /**

754  * ide_intr - default IDE interrupt handler

755  * @irq: interrupt number

756  * @dev_id: hwif

757  * @regs: unused weirdness from the kernel irq layer

758  *

759  * This is the default IRQ handler for the IDE layer. You should

760  * not need to override it. If you do be aware it is subtle in

761  * places

762  *

763  * hwif is the interface in the group currently performing

764  * a command. hwif->cur_dev is the drive and hwif->handler is

765  * the IRQ handler to call. As we issue a command the handlers

766  * step through multiple states, reassigning the handler to the

767  * next step in the process. Unlike a smart SCSI controller IDE

768  * expects the main processor to sequence the various transfer

769  * stages. We also manage a poll timer to catch up with most

770  * timeout situations. There are still a few where the handlers

771  * don't ever decide to give up.

772  *

773  * The handler eventually returns ide_stopped to indicate the

774  * request completed. At this point we issue the next request

775  * on the port and the process begins again.

776  */

777

778 irqreturn_t ide_intr (int irq, void *dev_id)

779 {

780 ide_hwif_t *hwif = (ide_hwif_t *)dev_id;

781 struct ide_host *host = hwif->host;

782 ide_drive_t *uninitialized_var(drive);

783 ide_handler_t *handler;

784 unsigned long flags;

785 ide_startstop_t startstop;

786 irqreturn_t irq_ret = IRQ_NONE;

787 int plug_device = 0;

788 struct request *uninitialized_var(rq_in_flight);

789

790 if (host->host_flags & IDE_HFLAG_SERIALIZE) {

791 if (hwif != host->cur_port)

792 goto out_early;

793 }

794

795 spin_lock_irqsave(&hwif->lock, flags);

796

797 if (hwif->port_ops && hwif->port_ops->test_irq &&

798     hwif->port_ops->test_irq(hwif) == 0)

799 goto out;

800

801 handler = hwif->handler;

802

803 if (handler == NULL || hwif->polling) {

804 /*

805  * Not expecting an interrupt from this drive.

806  * That means this could be:

807  * (1) an interrupt from another PCI device

808  * sharing the same PCI INT# as us.

809  * or (2) a drive just entered sleep or standby mode,

810  * and is interrupting to let us know.

811  * or (3) a spurious interrupt of unknown origin.

812  *

813  * For PCI, we cannot tell the difference,

814  * so in that case we just ignore it and hope it goes away.

815  */

816 if ((host->irq_flags & IRQF_SHARED) == 0) {

817 /*

818  * Probably not a shared PCI interrupt,

819  * so we can safely try to do something about it:

820  */

821 unexpected_intr(irq, hwif);

822 } else {

823 /*

824  * Whack the status register, just in case

825  * we have a leftover pending IRQ.

826  */

827 (void)hwif->tp_ops->read_status(hwif);

828 }

829 goto out;

830 }

831

832 drive = hwif->cur_dev;

833

834 if (!drive_is_ready(drive))

835 /*

836  * This happens regularly when we share a PCI IRQ with

837  * another device.  Unfortunately, it can also happen

838  * with some buggy drives that trigger the IRQ before

839  * their status register is up to date.  Hopefully we have

840  * enough advance overhead that the latter isn't a problem.

841  */

842 goto out;

843

844 hwif->handler = NULL;

845 hwif->expiry = NULL;

846 hwif->req_gen++;

847 del_timer(&hwif->timer);

848 spin_unlock(&hwif->lock);

849

850 if (hwif->port_ops && hwif->port_ops->clear_irq)

851 hwif->port_ops->clear_irq(drive);

852

853 if (drive->dev_flags & IDE_DFLAG_UNMASK)

854 local_irq_enable_in_hardirq();

855

856 /* service this interrupt, may set handler for next interrupt */

857 startstop = handler(drive);

858

859 spin_lock_irq(&hwif->lock);

860 /*

861  * Note that handler() may have set things up for another

862  * interrupt to occur soon, but it cannot happen until

863  * we exit from this routine, because it will be the

864  * same irq as is currently being serviced here, and Linux

865  * won't allow another of the same (on any CPU) until we return.

866  */

867 if (startstop == ide_stopped && hwif->polling == 0) {

868 BUG_ON(hwif->handler);

869 rq_in_flight = hwif->rq;

870 hwif->rq = NULL;

871 ide_unlock_port(hwif);

872 plug_device = 1;

873 }

874 irq_ret = IRQ_HANDLED;

875 out:

876 spin_unlock_irqrestore(&hwif->lock, flags);

877 out_early:

878 if (plug_device) {

879 ide_unlock_host(hwif->host);

880 ide_requeue_and_plug(drive, rq_in_flight);

881 }

882

883 return irq_ret;

884 }

从这段堪称和代码长度相媲美的注释来看,就足以让我们对他产生了恐惧。但是没有办法,不管前面是多大的火焰山,还是等扛过去呀。来看代码:

首先不说别的但从注释来看,这是整个ide所共享的一个中断向量。我们知道一般共享的中断向量都会有个dev_id来区分,不然岂不是乱了伦理。这里就是用hwif来区分了。

801 handler = hwif->handler;和我们上面__ide_set_handler450 hwif->handler= handler;相比是不是有种说不出的赤裸裸的美感呀。既然这么爽那么我们干脆就上到底把ide_intr857行一起看了857 startstop = handler(drive); 。这个时候你也许就感叹了,哎呀我的个妈呀,原来他们是有预谋有组织的在活动啊,的确内核他就喜欢干这样的勾当。说到这其实不想再往下说了,应该说已经解释清楚了智慧一想表达的观点。但是看到精美的内核代码,还是不禁多说两句..

844行注意一个细节,hwif->handler = NULL;因为这个中断函数是大家公共的,所以当一个任务执行完了以后hwif->handler是要被清除的,如果不清除这个向量在出现程序中803-830行所对应的这些情景的时候就会引发错误的操作,这是不允许的。

803-830行对应的情景代码的作者已经给了详细的注释,相信理解起来不算困难。

对于这个函数就说这么多了,接下来我们回到__ide_set_handler

智慧二:

451-453典型的定时器的操作,写过linux驱动代码的不会不知到这个大名鼎鼎的timer,同样知道timer的不会不知道他应该对应的有一个timer_handle。好的,这就对头了,与刚才的情况一样,让我们继续穿越时空来到上个世纪的ide-generic初始化。在ide_init_port_data函数中调用了这么一段,相信都已经忘怀了,还是贴出他相关的一小段。

1173 init_timer(&hwif->timer);

1174 hwif->timer.function = &ide_timer_expiry;

1175 hwif->timer.data = (unsigned long)hwif;

这段代码以一种很黄很暴力的方式告诉我们,如果你的设备超时了,那么不客气我就要调用ide_timer_expiry来解决了。不知道ide_timer_expiry和武汉的城管相比谁更加不得人心,那么我们还是来进去看看吧,不入虎穴,焉得虎子.

[ide-io.c]

607 /**

608  * ide_timer_expiry - handle lack of an IDE interrupt

609  * @data: timer callback magic (hwif)

610  *

611  * An IDE command has timed out before the expected drive return

612  * occurred. At this point we attempt to clean up the current

613  * mess. If the current handler includes an expiry handler then

614  * we invoke the expiry handler, and providing it is happy the

615  * work is done. If that fails we apply generic recovery rules

616  * invoking the handler and checking the drive DMA status. We

617  * have an excessively incestuous relationship with the DMA

618  * logic that wants cleaning up.

619  */

620  

621 void ide_timer_expiry (unsigned long data)

622 {

623 ide_hwif_t *hwif = (ide_hwif_t *)data;

624 ide_drive_t *uninitialized_var(drive);

625 ide_handler_t *handler;

626 unsigned long flags;

627 int wait = -1;

628 int plug_device = 0;

629 struct request *uninitialized_var(rq_in_flight);

630

631 spin_lock_irqsave(&hwif->lock, flags);

632

633 handler = hwif->handler;

634

635 if (handler == NULL || hwif->req_gen != hwif->req_gen_timer) {

636 /*

637  * Either a marginal timeout occurred

638  * (got the interrupt just as timer expired),

639  * or we were "sleeping" to give other devices a chance.

640  * Either way, we don't really want to complain about anything.

641  */

642 } else {

643 ide_expiry_t *expiry = hwif->expiry;

644 ide_startstop_t startstop = ide_stopped;

645

646 drive = hwif->cur_dev;

647

648 if (expiry) {

649 wait = expiry(drive);

650 if (wait > 0) { /* continue */

651 /* reset timer */

652 hwif->timer.expires = jiffies + wait;

653 hwif->req_gen_timer = hwif->req_gen;

654 add_timer(&hwif->timer);

655 spin_unlock_irqrestore(&hwif->lock, flags);

656 return;

657 }

658 }

659 hwif->handler = NULL;

660 hwif->expiry = NULL;

661 /*

662  * We need to simulate a real interrupt when invoking

663  * the handler() function, which means we need to

664  * globally mask the specific IRQ:

665  */

666 spin_unlock(&hwif->lock);

667 /* disable_irq_nosync ?? */

668 disable_irq(hwif->irq);

669 /* local CPU only, as if we were handling an interrupt */

670 local_irq_disable();

671 if (hwif->polling) {

672 startstop = handler(drive);

673 } else if (drive_is_ready(drive)) {

674 if (drive->waiting_for_dma)

675 hwif->dma_ops->dma_lost_irq(drive);

676 if (hwif->port_ops && hwif->port_ops->clear_irq)

677 hwif->port_ops->clear_irq(drive);

678

679 printk(KERN_WARNING "%s: lost interrupt/n",

680 drive->name);

681 startstop = handler(drive);

682 } else {

683 if (drive->waiting_for_dma)

684 startstop = ide_dma_timeout_retry(drive, wait);

685 else

686 startstop = ide_error(drive, "irq timeout",

687 hwif->tp_ops->read_status(hwif));

688 }

689 spin_lock_irq(&hwif->lock);

690 enable_irq(hwif->irq);

691 if (startstop == ide_stopped && hwif->polling == 0) {

692 rq_in_flight = hwif->rq;

693 hwif->rq = NULL;

694 ide_unlock_port(hwif);

695 plug_device = 1;

696 }

697 }

698 spin_unlock_irqrestore(&hwif->lock, flags);

699

700 if (plug_device) {

701 ide_unlock_host(hwif->host);

702 ide_requeue_and_plug(drive, rq_in_flight);

703 }

704 }

637-641行看到我说这几行,你可能有两个反应。第一是写错了,第二是有病。因为这时一段注释,说这段注释没有别的意思,就是因为第一眼看到他感觉这段话着实有点好笑。他大概的意思好像是说,“首先对于这个设备的超时我表示遗憾,我们也尽量去给这个设备新做人的机会,应为我们也不愿意看到他出现超时”。是不是颇有点老师的风范。

好了言归正传,648-658行我们确实看到了驱动给了设备新做人的机会。

659行前面也说过了,处理完中断这个hwif->handler 是要清空的,但是这里超时就是因为等待的中断没有到来,说以这里补上这个操作也是理所当然的了。

后面的代码也就比较简单了,既然超时了能补救的就补上,出了错的就报告错误的信息,一切都是本着对设备负责的态度。

苦海无边,该是回头的时候了。这样我们还是回到do_rw_taskfile中来,毕竟一切因果孽缘都始于她。说了这么久的handle还是来看一下task_no_data_intr,不然就对不起她了。

[ide-taskfile.c]

147 static ide_startstop_t task_no_data_intr(ide_drive_t *drive)

148 {

149 ide_hwif_t *hwif = drive->hwif;

150 struct ide_cmd *cmd = &hwif->cmd;

151 struct ide_taskfile *tf = &cmd->tf;

152 int custom = (cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0;

153 int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1;

154 u8 stat;

155

156 local_irq_enable_in_hardirq();

157

158 while (1) {

159 stat = hwif->tp_ops->read_status(hwif);

160 if ((stat & ATA_BUSY) == 0 || retries-- == 0)

161 break;

162 udelay(10);

163 };

164

165 if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {

166 if (custom && tf->command == ATA_CMD_SET_MULTI) {

167 drive->mult_req = drive->mult_count = 0;

168 drive->special_flags |= IDE_SFLAG_RECALIBRATE;

169 (void)ide_dump_status(drive, __func__, stat);

170 return ide_stopped;

171 } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS){

172 if ((stat & (ATA_ERR | ATA_DRQ)) == 0) {

173 ide_set_handler(drive, &task_no_data_intr,

174 WAIT_WORSTCASE);

175 return ide_started;

176 }

177 }

178 return ide_error(drive, "task_no_data_intr", stat);

179 }

180

181 if (custom && tf->command == ATA_CMD_SET_MULTI)

182 drive->mult_count = drive->mult_req;

183

184 if (custom == 0 || tf->command == ATA_CMD_IDLEIMMEDIATE ||

185     tf->command == ATA_CMD_CHK_POWER) {

186 struct request *rq = hwif->rq;

187

188 if (blk_pm_request(rq))

189 ide_complete_pm_rq(drive, rq);

190 else

191 ide_finish_cmd(drive, cmd, stat);

192 }

193

194 return ide_stopped;

195 }

我们知道对于nodata的命令等其实最终是完成一些状态的判断等工作,根据不同的命令返回状态的不同进行相应的处理,一旦出错就调用169178等行的出错处理。最后,我们来看一下191行的处理。

[ide-taskfile.c]

324 void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat)

325 {

326 struct request *rq = drive->hwif->rq;

327 u8 err = ide_read_error(drive), nsect = cmd->tf.nsect;

328 u8 set_xfer = !!(cmd->tf_flags & IDE_TFLAG_SET_XFER);

329

330 ide_complete_cmd(drive, cmd, stat, err);

331 rq->errors = err;

332

333 if (err == 0 && set_xfer) {

334 ide_set_xfer_rate(drive, nsect);

335 ide_driveid_update(drive);

336 }

337

338 ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq));

339 }

这个函数包含了两个方面的内容一个就是结束设备本身的命令操作,另外就是结束块设备那边的request。分别对应代码的330338行。

[ide-io.c]

74 void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)

75 {

76 const struct ide_tp_ops *tp_ops = drive->hwif->tp_ops;

77 struct ide_taskfile *tf = &cmd->tf;

78 struct request *rq = cmd->rq;

79 u8 tf_cmd = tf->command;

80

81 tf->error = err;

82 tf->status = stat;

83

84 if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {

85 u8 data[2];

86

87 tp_ops->input_data(drive, cmd, data, 2);

88

89 cmd->tf.data  = data[0];

90 cmd->hob.data = data[1];

91 }

92

93 ide_tf_readback(drive, cmd);

94

95 if ((cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) &&

96     tf_cmd == ATA_CMD_IDLEIMMEDIATE) {

97 if (tf->lbal != 0xc4) {

98 printk(KERN_ERR "%s: head unload failed!/n",

99        drive->name);

100 ide_tf_dump(drive->name, cmd);

101 } else

102 drive->dev_flags |= IDE_DFLAG_PARKED;

103 }

104

105 if (rq && rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {

106 struct ide_cmd *orig_cmd = rq->special;

107

108 if (cmd->tf_flags & IDE_TFLAG_DYN)

109 kfree(orig_cmd);

110 else

111 memcpy(orig_cmd, cmd, sizeof(*cmd));

112 }

113 }

这部分代码就不在详细说明了。

走来这么久整个ide驱动的构架也就基本上说完了,还是回到我们的这个故事的起点ide_disk_setup

接下来的事情就比较简单了,从ide_disk_setup返回以后重新回到ide_gd_probe。接下来就到了402行,add_disk(g);这个函数是块设备那边的一个接口,会将这个重要的gendisk结构注册到块设备中,然后IDE设备也就开启了一个新的时代……

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值