blk-settings: align max_sectors on "logical_block_size" boundary
[linux-2.6-microblaze.git] / block / blk-settings.c
index 9741d1d..b4aa2f3 100644 (file)
@@ -60,6 +60,7 @@ void blk_set_default_limits(struct queue_limits *lim)
        lim->io_opt = 0;
        lim->misaligned = 0;
        lim->zoned = BLK_ZONED_NONE;
+       lim->zone_write_granularity = 0;
 }
 EXPORT_SYMBOL(blk_set_default_limits);
 
@@ -157,10 +158,16 @@ void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_secto
                       __func__, max_hw_sectors);
        }
 
+       max_hw_sectors = round_down(max_hw_sectors,
+                                   limits->logical_block_size >> SECTOR_SHIFT);
        limits->max_hw_sectors = max_hw_sectors;
+
        max_sectors = min_not_zero(max_hw_sectors, limits->max_dev_sectors);
        max_sectors = min_t(unsigned int, max_sectors, BLK_DEF_MAX_SECTORS);
+       max_sectors = round_down(max_sectors,
+                                limits->logical_block_size >> SECTOR_SHIFT);
        limits->max_sectors = max_sectors;
+
        q->backing_dev_info->io_pages = max_sectors >> (PAGE_SHIFT - 9);
 }
 EXPORT_SYMBOL(blk_queue_max_hw_sectors);
@@ -321,13 +328,20 @@ EXPORT_SYMBOL(blk_queue_max_segment_size);
  **/
 void blk_queue_logical_block_size(struct request_queue *q, unsigned int size)
 {
-       q->limits.logical_block_size = size;
+       struct queue_limits *limits = &q->limits;
 
-       if (q->limits.physical_block_size < size)
-               q->limits.physical_block_size = size;
+       limits->logical_block_size = size;
 
-       if (q->limits.io_min < q->limits.physical_block_size)
-               q->limits.io_min = q->limits.physical_block_size;
+       if (limits->physical_block_size < size)
+               limits->physical_block_size = size;
+
+       if (limits->io_min < limits->physical_block_size)
+               limits->io_min = limits->physical_block_size;
+
+       limits->max_hw_sectors =
+               round_down(limits->max_hw_sectors, size >> SECTOR_SHIFT);
+       limits->max_sectors =
+               round_down(limits->max_sectors, size >> SECTOR_SHIFT);
 }
 EXPORT_SYMBOL(blk_queue_logical_block_size);
 
@@ -353,6 +367,28 @@ void blk_queue_physical_block_size(struct request_queue *q, unsigned int size)
 }
 EXPORT_SYMBOL(blk_queue_physical_block_size);
 
+/**
+ * blk_queue_zone_write_granularity - set zone write granularity for the queue
+ * @q:  the request queue for the zoned device
+ * @size:  the zone write granularity size, in bytes
+ *
+ * Description:
+ *   This should be set to the lowest possible size allowing to write in
+ *   sequential zones of a zoned block device.
+ */
+void blk_queue_zone_write_granularity(struct request_queue *q,
+                                     unsigned int size)
+{
+       if (WARN_ON_ONCE(!blk_queue_is_zoned(q)))
+               return;
+
+       q->limits.zone_write_granularity = size;
+
+       if (q->limits.zone_write_granularity < q->limits.logical_block_size)
+               q->limits.zone_write_granularity = q->limits.logical_block_size;
+}
+EXPORT_SYMBOL_GPL(blk_queue_zone_write_granularity);
+
 /**
  * blk_queue_alignment_offset - set physical block alignment offset
  * @q: the request queue for the device
@@ -468,6 +504,14 @@ void blk_queue_io_opt(struct request_queue *q, unsigned int opt)
 }
 EXPORT_SYMBOL(blk_queue_io_opt);
 
+static unsigned int blk_round_down_sectors(unsigned int sectors, unsigned int lbs)
+{
+       sectors = round_down(sectors, lbs >> SECTOR_SHIFT);
+       if (sectors < PAGE_SIZE >> SECTOR_SHIFT)
+               sectors = PAGE_SIZE >> SECTOR_SHIFT;
+       return sectors;
+}
+
 /**
  * blk_stack_limits - adjust queue_limits for stacked devices
  * @t: the stacking driver limits (top device)
@@ -547,7 +591,10 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
 
        t->io_min = max(t->io_min, b->io_min);
        t->io_opt = lcm_not_zero(t->io_opt, b->io_opt);
-       t->chunk_sectors = lcm_not_zero(t->chunk_sectors, b->chunk_sectors);
+
+       /* Set non-power-of-2 compatible chunk_sectors boundary */
+       if (b->chunk_sectors)
+               t->chunk_sectors = gcd(t->chunk_sectors, b->chunk_sectors);
 
        /* Physical block size a multiple of the logical block size? */
        if (t->physical_block_size & (t->logical_block_size - 1)) {
@@ -591,6 +638,10 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                ret = -1;
        }
 
+       t->max_sectors = blk_round_down_sectors(t->max_sectors, t->logical_block_size);
+       t->max_hw_sectors = blk_round_down_sectors(t->max_hw_sectors, t->logical_block_size);
+       t->max_dev_sectors = blk_round_down_sectors(t->max_dev_sectors, t->logical_block_size);
+
        /* Discard alignment and granularity */
        if (b->discard_granularity) {
                alignment = queue_limit_discard_alignment(b, start);
@@ -615,6 +666,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                        t->discard_granularity;
        }
 
+       t->zone_write_granularity = max(t->zone_write_granularity,
+                                       b->zone_write_granularity);
        t->zoned = max(t->zoned, b->zoned);
        return ret;
 }
@@ -831,6 +884,8 @@ EXPORT_SYMBOL_GPL(blk_queue_can_use_dma_map_merging);
  */
 void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
 {
+       struct request_queue *q = disk->queue;
+
        switch (model) {
        case BLK_ZONED_HM:
                /*
@@ -849,7 +904,7 @@ void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
                 * we do nothing special as far as the block layer is concerned.
                 */
                if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED) ||
-                   disk_has_partitions(disk))
+                   !xa_empty(&disk->part_tbl))
                        model = BLK_ZONED_NONE;
                break;
        case BLK_ZONED_NONE:
@@ -859,7 +914,17 @@ void blk_queue_set_zoned(struct gendisk *disk, enum blk_zoned_model model)
                break;
        }
 
-       disk->queue->limits.zoned = model;
+       q->limits.zoned = model;
+       if (model != BLK_ZONED_NONE) {
+               /*
+                * Set the zone write granularity to the device logical block
+                * size by default. The driver can change this value if needed.
+                */
+               blk_queue_zone_write_granularity(q,
+                                               queue_logical_block_size(q));
+       } else {
+               blk_queue_clear_zone_settings(q);
+       }
 }
 EXPORT_SYMBOL_GPL(blk_queue_set_zoned);