diff options
-rw-r--r-- | drivers/block/cciss.c | 98 |
1 files changed, 59 insertions, 39 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index ee7cfde8a145..17e420c13b36 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -3830,54 +3830,36 @@ static void __devinit cciss_wait_for_mode_change_ack(ctlr_info_t *h) | |||
3830 | } | 3830 | } |
3831 | } | 3831 | } |
3832 | 3832 | ||
3833 | static void __devinit cciss_put_controller_into_performant_mode(ctlr_info_t *h) | 3833 | static __devinit void cciss_enter_performant_mode(ctlr_info_t *h) |
3834 | { | 3834 | { |
3835 | __u32 trans_support; | 3835 | /* This is a bit complicated. There are 8 registers on |
3836 | * the controller which we write to to tell it 8 different | ||
3837 | * sizes of commands which there may be. It's a way of | ||
3838 | * reducing the DMA done to fetch each command. Encoded into | ||
3839 | * each command's tag are 3 bits which communicate to the controller | ||
3840 | * which of the eight sizes that command fits within. The size of | ||
3841 | * each command depends on how many scatter gather entries there are. | ||
3842 | * Each SG entry requires 16 bytes. The eight registers are programmed | ||
3843 | * with the number of 16-byte blocks a command of that size requires. | ||
3844 | * The smallest command possible requires 5 such 16 byte blocks. | ||
3845 | * the largest command possible requires MAXSGENTRIES + 4 16-byte | ||
3846 | * blocks. Note, this only extends to the SG entries contained | ||
3847 | * within the command block, and does not extend to chained blocks | ||
3848 | * of SG elements. bft[] contains the eight values we write to | ||
3849 | * the registers. They are not evenly distributed, but have more | ||
3850 | * sizes for small commands, and fewer sizes for larger commands. | ||
3851 | */ | ||
3836 | __u32 trans_offset; | 3852 | __u32 trans_offset; |
3853 | int bft[8] = { 5, 6, 8, 10, 12, 20, 28, MAXSGENTRIES + 4}; | ||
3837 | /* | 3854 | /* |
3838 | * 5 = 1 s/g entry or 4k | 3855 | * 5 = 1 s/g entry or 4k |
3839 | * 6 = 2 s/g entry or 8k | 3856 | * 6 = 2 s/g entry or 8k |
3840 | * 8 = 4 s/g entry or 16k | 3857 | * 8 = 4 s/g entry or 16k |
3841 | * 10 = 6 s/g entry or 24k | 3858 | * 10 = 6 s/g entry or 24k |
3842 | */ | 3859 | */ |
3843 | int bft[8] = { 5, 6, 8, 10, 12, 20, 28, MAXSGENTRIES + 4}; | ||
3844 | unsigned long register_value; | 3860 | unsigned long register_value; |
3845 | |||
3846 | BUILD_BUG_ON(28 > MAXSGENTRIES + 4); | 3861 | BUILD_BUG_ON(28 > MAXSGENTRIES + 4); |
3847 | 3862 | ||
3848 | dev_dbg(&h->pdev->dev, "Trying to put board into Performant mode\n"); | ||
3849 | /* Attempt to put controller into performant mode if supported */ | ||
3850 | /* Does board support performant mode? */ | ||
3851 | trans_support = readl(&(h->cfgtable->TransportSupport)); | ||
3852 | if (!(trans_support & PERFORMANT_MODE)) | ||
3853 | return; | ||
3854 | |||
3855 | printk(KERN_WARNING "cciss%d: Placing controller into " | ||
3856 | "performant mode\n", h->ctlr); | ||
3857 | /* Performant mode demands commands on a 32 byte boundary | ||
3858 | * pci_alloc_consistent aligns on page boundarys already. | ||
3859 | * Just need to check if divisible by 32 | ||
3860 | */ | ||
3861 | if ((sizeof(CommandList_struct) % 32) != 0) { | ||
3862 | printk(KERN_WARNING "%s %d %s\n", | ||
3863 | "cciss info: command size[", | ||
3864 | (int)sizeof(CommandList_struct), | ||
3865 | "] not divisible by 32, no performant mode..\n"); | ||
3866 | return; | ||
3867 | } | ||
3868 | |||
3869 | /* Performant mode ring buffer and supporting data structures */ | ||
3870 | h->reply_pool = (__u64 *)pci_alloc_consistent( | ||
3871 | h->pdev, h->max_commands * sizeof(__u64), | ||
3872 | &(h->reply_pool_dhandle)); | ||
3873 | |||
3874 | /* Need a block fetch table for performant mode */ | ||
3875 | h->blockFetchTable = kmalloc(((h->maxsgentries+1) * | ||
3876 | sizeof(__u32)), GFP_KERNEL); | ||
3877 | |||
3878 | if ((h->reply_pool == NULL) || (h->blockFetchTable == NULL)) | ||
3879 | goto clean_up; | ||
3880 | |||
3881 | h->reply_pool_wraparound = 1; /* spec: init to 1 */ | 3863 | h->reply_pool_wraparound = 1; /* spec: init to 1 */ |
3882 | 3864 | ||
3883 | /* Controller spec: zero out this buffer. */ | 3865 | /* Controller spec: zero out this buffer. */ |
@@ -3906,18 +3888,56 @@ static void __devinit cciss_put_controller_into_performant_mode(ctlr_info_t *h) | |||
3906 | writel(CFGTBL_Trans_Performant, | 3888 | writel(CFGTBL_Trans_Performant, |
3907 | &(h->cfgtable->HostWrite.TransportRequest)); | 3889 | &(h->cfgtable->HostWrite.TransportRequest)); |
3908 | 3890 | ||
3909 | h->transMethod = CFGTBL_Trans_Performant; | ||
3910 | writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); | 3891 | writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); |
3911 | cciss_wait_for_mode_change_ack(h); | 3892 | cciss_wait_for_mode_change_ack(h); |
3912 | register_value = readl(&(h->cfgtable->TransportActive)); | 3893 | register_value = readl(&(h->cfgtable->TransportActive)); |
3913 | if (!(register_value & CFGTBL_Trans_Performant)) { | 3894 | if (!(register_value & CFGTBL_Trans_Performant)) |
3914 | printk(KERN_WARNING "cciss: unable to get board into" | 3895 | printk(KERN_WARNING "cciss: unable to get board into" |
3915 | " performant mode\n"); | 3896 | " performant mode\n"); |
3897 | } | ||
3898 | |||
3899 | static void __devinit cciss_put_controller_into_performant_mode(ctlr_info_t *h) | ||
3900 | { | ||
3901 | __u32 trans_support; | ||
3902 | |||
3903 | dev_dbg(&h->pdev->dev, "Trying to put board into Performant mode\n"); | ||
3904 | /* Attempt to put controller into performant mode if supported */ | ||
3905 | /* Does board support performant mode? */ | ||
3906 | trans_support = readl(&(h->cfgtable->TransportSupport)); | ||
3907 | if (!(trans_support & PERFORMANT_MODE)) | ||
3908 | return; | ||
3909 | |||
3910 | printk(KERN_WARNING "cciss%d: Placing controller into " | ||
3911 | "performant mode\n", h->ctlr); | ||
3912 | /* Performant mode demands commands on a 32 byte boundary | ||
3913 | * pci_alloc_consistent aligns on page boundarys already. | ||
3914 | * Just need to check if divisible by 32 | ||
3915 | */ | ||
3916 | if ((sizeof(CommandList_struct) % 32) != 0) { | ||
3917 | printk(KERN_WARNING "%s %d %s\n", | ||
3918 | "cciss info: command size[", | ||
3919 | (int)sizeof(CommandList_struct), | ||
3920 | "] not divisible by 32, no performant mode..\n"); | ||
3916 | return; | 3921 | return; |
3917 | } | 3922 | } |
3918 | 3923 | ||
3924 | /* Performant mode ring buffer and supporting data structures */ | ||
3925 | h->reply_pool = (__u64 *)pci_alloc_consistent( | ||
3926 | h->pdev, h->max_commands * sizeof(__u64), | ||
3927 | &(h->reply_pool_dhandle)); | ||
3928 | |||
3929 | /* Need a block fetch table for performant mode */ | ||
3930 | h->blockFetchTable = kmalloc(((h->maxsgentries+1) * | ||
3931 | sizeof(__u32)), GFP_KERNEL); | ||
3932 | |||
3933 | if ((h->reply_pool == NULL) || (h->blockFetchTable == NULL)) | ||
3934 | goto clean_up; | ||
3935 | |||
3936 | cciss_enter_performant_mode(h); | ||
3937 | |||
3919 | /* Change the access methods to the performant access methods */ | 3938 | /* Change the access methods to the performant access methods */ |
3920 | h->access = SA5_performant_access; | 3939 | h->access = SA5_performant_access; |
3940 | h->transMethod = CFGTBL_Trans_Performant; | ||
3921 | 3941 | ||
3922 | return; | 3942 | return; |
3923 | clean_up: | 3943 | clean_up: |