From d2f7cbe7b26a74dbbbf8f325b2a6fd01bc34032c Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Thu, 31 Oct 2013 17:25:08 +0100 Subject: x86/efi: Runtime services virtual mapping We map the EFI regions needed for runtime services non-contiguously, with preserved alignment on virtual addresses starting from -4G down for a total max space of 64G. This way, we provide for stable runtime services addresses across kernels so that a kexec'd kernel can still use them. Thus, they're mapped in a separate pagetable so that we don't pollute the kernel namespace. Add an efi= kernel command line parameter for passing miscellaneous options and chicken bits from the command line. While at it, add a chicken bit called "efi=old_map" which can be used as a fallback to the old runtime services mapping method in case there's some b0rkage with a particular EFI implementation (haha, it is hard to hold up the sarcasm here...). Also, add the UEFI RT VA space to Documentation/x86/x86_64/mm.txt. Signed-off-by: Borislav Petkov Signed-off-by: Matt Fleming --- include/linux/efi.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/efi.h b/include/linux/efi.h index bc5687d0f315..6c0ca528300c 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -653,6 +653,7 @@ extern int __init efi_setup_pcdp_console(char *); #define EFI_RUNTIME_SERVICES 3 /* Can we use runtime services? */ #define EFI_MEMMAP 4 /* Can we use EFI memory map? */ #define EFI_64BIT 5 /* Is the firmware 64-bit? */ +#define EFI_ARCH_1 6 /* First arch-specific bit */ #ifdef CONFIG_EFI # ifdef CONFIG_X86 -- cgit v1.2.3-59-g8ed1b From 64528d03d7233800ec77f1acb9222cf090f926ca Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 30 Oct 2013 22:48:00 +0000 Subject: iio: hid-sensors: accelerometer: Add sensitivity A number of Properties that can be applied to Data Fields are per data field basis or for all data fields. Adding sensitivity field for all accelerometer fields, which is most commonly used in currently available sensor hubs. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/accel/hid-sensor-accel-3d.c | 12 ++++++++++++ include/linux/hid-sensor-ids.h | 5 +++++ 2 files changed, 17 insertions(+) (limited to 'include/linux') diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c index dcda17395c4e..6b8735ce8345 100644 --- a/drivers/iio/accel/hid-sensor-accel-3d.c +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -262,6 +262,18 @@ static int accel_3d_parse_report(struct platform_device *pdev, st->accel[1].index, st->accel[1].report_id, st->accel[2].index, st->accel[2].report_id); + /* Set Sensitivity field ids, when there is no individual modifier */ + if (st->common_attributes.sensitivity.index < 0) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_DATA_ACCELERATION, + &st->common_attributes.sensitivity); + dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", + st->common_attributes.sensitivity.index, + st->common_attributes.sensitivity.report_id); + } + return ret; } diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 4f945d3ed49f..4dda3b791c82 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -23,6 +23,7 @@ /* Accel 3D (200073) */ #define HID_USAGE_SENSOR_ACCEL_3D 0x200073 +#define HID_USAGE_SENSOR_DATA_ACCELERATION 0x200452 #define HID_USAGE_SENSOR_ACCEL_X_AXIS 0x200453 #define HID_USAGE_SENSOR_ACCEL_Y_AXIS 0x200454 #define HID_USAGE_SENSOR_ACCEL_Z_AXIS 0x200455 @@ -117,4 +118,8 @@ #define HID_USAGE_SENSOR_PROP_REPORT_STATE 0x200316 #define HID_USAGE_SENSOR_PROY_POWER_STATE 0x200319 +/* Per data field properties */ +#define HID_USAGE_SENSOR_DATA_MOD_NONE 0x00 +#define HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS 0x1000 + #endif -- cgit v1.2.3-59-g8ed1b From 2371aebf027b86d740e40b47c813be8474500bcd Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 30 Oct 2013 22:48:00 +0000 Subject: iio: hid-sensors: gyro : Add sensitivity A number of Properties that can be applied to Data Fields are per data field basis or for all data fields. Adding sensitivity field for all gyro fields, which is most commonly used in currently available sensor hubs. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/gyro/hid-sensor-gyro-3d.c | 11 +++++++++++ include/linux/hid-sensor-ids.h | 1 + 2 files changed, 12 insertions(+) (limited to 'include/linux') diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c index ea01c6bcfb56..97797dbaad34 100644 --- a/drivers/iio/gyro/hid-sensor-gyro-3d.c +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -262,6 +262,17 @@ static int gyro_3d_parse_report(struct platform_device *pdev, st->gyro[1].index, st->gyro[1].report_id, st->gyro[2].index, st->gyro[2].report_id); + /* Set Sensitivity field ids, when there is no individual modifier */ + if (st->common_attributes.sensitivity.index < 0) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_DATA_ANGL_VELOCITY, + &st->common_attributes.sensitivity); + dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", + st->common_attributes.sensitivity.index, + st->common_attributes.sensitivity.report_id); + } return ret; } diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 4dda3b791c82..f3ed6b14f86c 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -34,6 +34,7 @@ /* Gyro 3D: (200076) */ #define HID_USAGE_SENSOR_GYRO_3D 0x200076 +#define HID_USAGE_SENSOR_DATA_ANGL_VELOCITY 0x200456 #define HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS 0x200457 #define HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS 0x200458 #define HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS 0x200459 -- cgit v1.2.3-59-g8ed1b From f87ee1bd888e0f6b9179c569b60d2c92c0000bc8 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 30 Oct 2013 22:48:00 +0000 Subject: iio: hid-sensors: light/als : Add sensitivity A number of Properties that can be applied to Data Fields are per data field basis or for all data fields. Adding sensitivity field for all als fields, which is most commonly used in currently available sensor hubs. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/light/hid-sensor-als.c | 11 +++++++++++ include/linux/hid-sensor-ids.h | 1 + 2 files changed, 12 insertions(+) (limited to 'include/linux') diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c index fa6ae8cf89ea..0c7f115ee3b3 100644 --- a/drivers/iio/light/hid-sensor-als.c +++ b/drivers/iio/light/hid-sensor-als.c @@ -229,6 +229,17 @@ static int als_parse_report(struct platform_device *pdev, dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index, st->als_illum.report_id); + /* Set Sensitivity field ids, when there is no individual modifier */ + if (st->common_attributes.sensitivity.index < 0) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_DATA_LIGHT, + &st->common_attributes.sensitivity); + dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", + st->common_attributes.sensitivity.index, + st->common_attributes.sensitivity.report_id); + } return ret; } diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index f3ed6b14f86c..8d45e0290c91 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -30,6 +30,7 @@ /* ALS (200041) */ #define HID_USAGE_SENSOR_ALS 0x200041 +#define HID_USAGE_SENSOR_DATA_LIGHT 0x2004d0 #define HID_USAGE_SENSOR_LIGHT_ILLUM 0x2004d1 /* Gyro 3D: (200076) */ -- cgit v1.2.3-59-g8ed1b From 2461fc9f3f45828eee23dd5018e7b5576aceec80 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 6 Nov 2013 00:11:00 +0000 Subject: iio: hid-sensors: magnetometer : Add sensitivity A number of Properties that can be applied to Data Fields are per data field basis or for all data fields. Adding sensitivity field for all magnetometer fields, which is most commonly used in currently available sensor hubs. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/magnetometer/hid-sensor-magn-3d.c | 12 ++++++++++++ include/linux/hid-sensor-ids.h | 1 + 2 files changed, 13 insertions(+) (limited to 'include/linux') diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c index 2634920562fb..67fce1916d21 100644 --- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -263,6 +263,18 @@ static int magn_3d_parse_report(struct platform_device *pdev, st->magn[1].index, st->magn[1].report_id, st->magn[2].index, st->magn[2].report_id); + /* Set Sensitivity field ids, when there is no individual modifier */ + if (st->common_attributes.sensitivity.index < 0) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_DATA_ORIENTATION, + &st->common_attributes.sensitivity); + dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", + st->common_attributes.sensitivity.index, + st->common_attributes.sensitivity.report_id); + } + return ret; } diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 8d45e0290c91..4cc165887b09 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -42,6 +42,7 @@ /* ORIENTATION: Compass 3D: (200083) */ #define HID_USAGE_SENSOR_COMPASS_3D 0x200083 +#define HID_USAGE_SENSOR_DATA_ORIENTATION 0x200470 #define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING 0x200471 #define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING_X 0x200472 #define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING_Y 0x200473 -- cgit v1.2.3-59-g8ed1b From b80d5ccca3a012e91ca64a2a0b13049163a6a698 Mon Sep 17 00:00:00 2001 From: Haiyan Hu Date: Tue, 10 Sep 2013 11:25:37 +0800 Subject: NVMe: Avoid shift operation when writing cq head doorbell Changes the type of dev->db_stride to unsigned and changes the value stored there to be 1 << the current value. Then there is less calculation to be done at completion time. Signed-off-by: Haiyan Hu Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 10 +++++----- include/linux/nvme.h | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 26d03fa0bf26..073aec913c78 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -775,7 +775,7 @@ static int nvme_process_cq(struct nvme_queue *nvmeq) if (head == nvmeq->cq_head && phase == nvmeq->cq_phase) return 0; - writel(head, nvmeq->q_db + (1 << nvmeq->dev->db_stride)); + writel(head, nvmeq->q_db + nvmeq->dev->db_stride); nvmeq->cq_head = head; nvmeq->cq_phase = phase; @@ -1113,7 +1113,7 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, init_waitqueue_head(&nvmeq->sq_full); init_waitqueue_entry(&nvmeq->sq_cong_wait, nvme_thread); bio_list_init(&nvmeq->sq_cong); - nvmeq->q_db = &dev->dbs[qid << (dev->db_stride + 1)]; + nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride]; nvmeq->q_depth = depth; nvmeq->cq_vector = vector; nvmeq->q_suspended = 1; @@ -1149,7 +1149,7 @@ static void nvme_init_queue(struct nvme_queue *nvmeq, u16 qid) nvmeq->sq_tail = 0; nvmeq->cq_head = 0; nvmeq->cq_phase = 1; - nvmeq->q_db = &dev->dbs[qid << (dev->db_stride + 1)]; + nvmeq->q_db = &dev->dbs[qid * 2 * dev->db_stride]; memset(nvmeq->cmdid_data, 0, extra); memset((void *)nvmeq->cqes, 0, CQ_SIZE(nvmeq->q_depth)); nvme_cancel_ios(nvmeq, false); @@ -1741,7 +1741,7 @@ static int set_queue_count(struct nvme_dev *dev, int count) static size_t db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues) { - return 4096 + ((nr_io_queues + 1) << (dev->db_stride + 3)); + return 4096 + ((nr_io_queues + 1) * 8 * dev->db_stride); } static int nvme_setup_io_queues(struct nvme_dev *dev) @@ -1958,7 +1958,7 @@ static int nvme_dev_map(struct nvme_dev *dev) if (!dev->bar) goto disable; - dev->db_stride = NVME_CAP_STRIDE(readq(&dev->bar->cap)); + dev->db_stride = 1 << NVME_CAP_STRIDE(readq(&dev->bar->cap)); dev->dbs = ((void __iomem *)dev->bar) + 4096; return 0; diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 26ebcf41c213..8119a476cb29 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -80,7 +80,7 @@ struct nvme_dev { struct dma_pool *prp_small_pool; int instance; int queue_count; - int db_stride; + u32 db_stride; u32 ctrl_config; struct msix_entry *entry; struct nvme_bar __iomem *bar; -- cgit v1.2.3-59-g8ed1b From e64001e8efc107992fd835770f6383d0dc731594 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 20 Nov 2013 13:17:07 +0000 Subject: ASoC: wm5110: Add extra AIF2 channels Signed-off-by: D.J. Barrow Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- include/linux/mfd/arizona/registers.h | 121 ++++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.c | 8 +++ sound/soc/codecs/arizona.h | 2 +- sound/soc/codecs/wm5110.c | 48 +++++++++++++- 4 files changed, 176 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 4706d3d46e56..8f4c9d77ab20 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -511,6 +511,38 @@ #define ARIZONA_AIF2TX2MIX_INPUT_3_VOLUME 0x74D #define ARIZONA_AIF2TX2MIX_INPUT_4_SOURCE 0x74E #define ARIZONA_AIF2TX2MIX_INPUT_4_VOLUME 0x74F +#define ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE 0x750 +#define ARIZONA_AIF2TX3MIX_INPUT_1_VOLUME 0x751 +#define ARIZONA_AIF2TX3MIX_INPUT_2_SOURCE 0x752 +#define ARIZONA_AIF2TX3MIX_INPUT_2_VOLUME 0x753 +#define ARIZONA_AIF2TX3MIX_INPUT_3_SOURCE 0x754 +#define ARIZONA_AIF2TX3MIX_INPUT_3_VOLUME 0x755 +#define ARIZONA_AIF2TX3MIX_INPUT_4_SOURCE 0x756 +#define ARIZONA_AIF2TX3MIX_INPUT_4_VOLUME 0x757 +#define ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE 0x758 +#define ARIZONA_AIF2TX4MIX_INPUT_1_VOLUME 0x759 +#define ARIZONA_AIF2TX4MIX_INPUT_2_SOURCE 0x75A +#define ARIZONA_AIF2TX4MIX_INPUT_2_VOLUME 0x75B +#define ARIZONA_AIF2TX4MIX_INPUT_3_SOURCE 0x75C +#define ARIZONA_AIF2TX4MIX_INPUT_3_VOLUME 0x75D +#define ARIZONA_AIF2TX4MIX_INPUT_4_SOURCE 0x75E +#define ARIZONA_AIF2TX4MIX_INPUT_4_VOLUME 0x75F +#define ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE 0x760 +#define ARIZONA_AIF2TX5MIX_INPUT_1_VOLUME 0x761 +#define ARIZONA_AIF2TX5MIX_INPUT_2_SOURCE 0x762 +#define ARIZONA_AIF2TX5MIX_INPUT_2_VOLUME 0x763 +#define ARIZONA_AIF2TX5MIX_INPUT_3_SOURCE 0x764 +#define ARIZONA_AIF2TX5MIX_INPUT_3_VOLUME 0x765 +#define ARIZONA_AIF2TX5MIX_INPUT_4_SOURCE 0x766 +#define ARIZONA_AIF2TX5MIX_INPUT_4_VOLUME 0x767 +#define ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE 0x768 +#define ARIZONA_AIF2TX6MIX_INPUT_1_VOLUME 0x769 +#define ARIZONA_AIF2TX6MIX_INPUT_2_SOURCE 0x76A +#define ARIZONA_AIF2TX6MIX_INPUT_2_VOLUME 0x76B +#define ARIZONA_AIF2TX6MIX_INPUT_3_SOURCE 0x76C +#define ARIZONA_AIF2TX6MIX_INPUT_3_VOLUME 0x76D +#define ARIZONA_AIF2TX6MIX_INPUT_4_SOURCE 0x76E +#define ARIZONA_AIF2TX6MIX_INPUT_4_VOLUME 0x76F #define ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE 0x780 #define ARIZONA_AIF3TX1MIX_INPUT_1_VOLUME 0x781 #define ARIZONA_AIF3TX1MIX_INPUT_2_SOURCE 0x782 @@ -3725,6 +3757,35 @@ #define ARIZONA_AIF2TX2_SLOT_SHIFT 0 /* AIF2TX2_SLOT - [5:0] */ #define ARIZONA_AIF2TX2_SLOT_WIDTH 6 /* AIF2TX2_SLOT - [5:0] */ +/* + * R1355 (0x54B) - AIF2 Frame Ctrl 5 + */ +#define ARIZONA_AIF2TX3_SLOT_MASK 0x003F /* AIF2TX3_SLOT - [5:0] */ +#define ARIZONA_AIF2TX3_SLOT_SHIFT 0 /* AIF2TX3_SLOT - [5:0] */ +#define ARIZONA_AIF2TX3_SLOT_WIDTH 6 /* AIF2TX3_SLOT - [5:0] */ + +/* + * R1356 (0x54C) - AIF2 Frame Ctrl 6 + */ +#define ARIZONA_AIF2TX4_SLOT_MASK 0x003F /* AIF2TX4_SLOT - [5:0] */ +#define ARIZONA_AIF2TX4_SLOT_SHIFT 0 /* AIF2TX4_SLOT - [5:0] */ +#define ARIZONA_AIF2TX4_SLOT_WIDTH 6 /* AIF2TX4_SLOT - [5:0] */ + + +/* + * R1357 (0x54D) - AIF2 Frame Ctrl 7 + */ +#define ARIZONA_AIF2TX5_SLOT_MASK 0x003F /* AIF2TX5_SLOT - [5:0] */ +#define ARIZONA_AIF2TX5_SLOT_SHIFT 0 /* AIF2TX5_SLOT - [5:0] */ +#define ARIZONA_AIF2TX5_SLOT_WIDTH 6 /* AIF2TX5_SLOT - [5:0] */ + +/* + * R1358 (0x54E) - AIF2 Frame Ctrl 8 + */ +#define ARIZONA_AIF2TX6_SLOT_MASK 0x003F /* AIF2TX6_SLOT - [5:0] */ +#define ARIZONA_AIF2TX6_SLOT_SHIFT 0 /* AIF2TX6_SLOT - [5:0] */ +#define ARIZONA_AIF2TX6_SLOT_WIDTH 6 /* AIF2TX6_SLOT - [5:0] */ + /* * R1361 (0x551) - AIF2 Frame Ctrl 11 */ @@ -3739,9 +3800,53 @@ #define ARIZONA_AIF2RX2_SLOT_SHIFT 0 /* AIF2RX2_SLOT - [5:0] */ #define ARIZONA_AIF2RX2_SLOT_WIDTH 6 /* AIF2RX2_SLOT - [5:0] */ +/* + * R1363 (0x553) - AIF2 Frame Ctrl 13 + */ +#define ARIZONA_AIF2RX3_SLOT_MASK 0x003F /* AIF2RX3_SLOT - [5:0] */ +#define ARIZONA_AIF2RX3_SLOT_SHIFT 0 /* AIF2RX3_SLOT - [5:0] */ +#define ARIZONA_AIF2RX3_SLOT_WIDTH 6 /* AIF2RX3_SLOT - [5:0] */ + +/* + * R1364 (0x554) - AIF2 Frame Ctrl 14 + */ +#define ARIZONA_AIF2RX4_SLOT_MASK 0x003F /* AIF2RX4_SLOT - [5:0] */ +#define ARIZONA_AIF2RX4_SLOT_SHIFT 0 /* AIF2RX4_SLOT - [5:0] */ +#define ARIZONA_AIF2RX4_SLOT_WIDTH 6 /* AIF2RX4_SLOT - [5:0] */ + +/* + * R1365 (0x555) - AIF2 Frame Ctrl 15 + */ +#define ARIZONA_AIF2RX5_SLOT_MASK 0x003F /* AIF2RX5_SLOT - [5:0] */ +#define ARIZONA_AIF2RX5_SLOT_SHIFT 0 /* AIF2RX5_SLOT - [5:0] */ +#define ARIZONA_AIF2RX5_SLOT_WIDTH 6 /* AIF2RX5_SLOT - [5:0] */ + +/* + * R1366 (0x556) - AIF2 Frame Ctrl 16 + */ +#define ARIZONA_AIF2RX6_SLOT_MASK 0x003F /* AIF2RX6_SLOT - [5:0] */ +#define ARIZONA_AIF2RX6_SLOT_SHIFT 0 /* AIF2RX6_SLOT - [5:0] */ +#define ARIZONA_AIF2RX6_SLOT_WIDTH 6 /* AIF2RX6_SLOT - [5:0] */ + /* * R1369 (0x559) - AIF2 Tx Enables */ +#define ARIZONA_AIF2TX6_ENA 0x0020 /* AIF2TX6_ENA */ +#define ARIZONA_AIF2TX6_ENA_MASK 0x0020 /* AIF2TX6_ENA */ +#define ARIZONA_AIF2TX6_ENA_SHIFT 5 /* AIF2TX6_ENA */ +#define ARIZONA_AIF2TX6_ENA_WIDTH 1 /* AIF2TX6_ENA */ +#define ARIZONA_AIF2TX5_ENA 0x0010 /* AIF2TX5_ENA */ +#define ARIZONA_AIF2TX5_ENA_MASK 0x0010 /* AIF2TX5_ENA */ +#define ARIZONA_AIF2TX5_ENA_SHIFT 4 /* AIF2TX5_ENA */ +#define ARIZONA_AIF2TX5_ENA_WIDTH 1 /* AIF2TX5_ENA */ +#define ARIZONA_AIF2TX4_ENA 0x0008 /* AIF2TX4_ENA */ +#define ARIZONA_AIF2TX4_ENA_MASK 0x0008 /* AIF2TX4_ENA */ +#define ARIZONA_AIF2TX4_ENA_SHIFT 3 /* AIF2TX4_ENA */ +#define ARIZONA_AIF2TX4_ENA_WIDTH 1 /* AIF2TX4_ENA */ +#define ARIZONA_AIF2TX3_ENA 0x0004 /* AIF2TX3_ENA */ +#define ARIZONA_AIF2TX3_ENA_MASK 0x0004 /* AIF2TX3_ENA */ +#define ARIZONA_AIF2TX3_ENA_SHIFT 2 /* AIF2TX3_ENA */ +#define ARIZONA_AIF2TX3_ENA_WIDTH 1 /* AIF2TX3_ENA */ #define ARIZONA_AIF2TX2_ENA 0x0002 /* AIF2TX2_ENA */ #define ARIZONA_AIF2TX2_ENA_MASK 0x0002 /* AIF2TX2_ENA */ #define ARIZONA_AIF2TX2_ENA_SHIFT 1 /* AIF2TX2_ENA */ @@ -3754,6 +3859,22 @@ /* * R1370 (0x55A) - AIF2 Rx Enables */ +#define ARIZONA_AIF2RX6_ENA 0x0020 /* AIF2RX6_ENA */ +#define ARIZONA_AIF2RX6_ENA_MASK 0x0020 /* AIF2RX6_ENA */ +#define ARIZONA_AIF2RX6_ENA_SHIFT 5 /* AIF2RX6_ENA */ +#define ARIZONA_AIF2RX6_ENA_WIDTH 1 /* AIF2RX6_ENA */ +#define ARIZONA_AIF2RX5_ENA 0x0010 /* AIF2RX5_ENA */ +#define ARIZONA_AIF2RX5_ENA_MASK 0x0010 /* AIF2RX5_ENA */ +#define ARIZONA_AIF2RX5_ENA_SHIFT 4 /* AIF2RX5_ENA */ +#define ARIZONA_AIF2RX5_ENA_WIDTH 1 /* AIF2RX5_ENA */ +#define ARIZONA_AIF2RX4_ENA 0x0008 /* AIF2RX4_ENA */ +#define ARIZONA_AIF2RX4_ENA_MASK 0x0008 /* AIF2RX4_ENA */ +#define ARIZONA_AIF2RX4_ENA_SHIFT 3 /* AIF2RX4_ENA */ +#define ARIZONA_AIF2RX4_ENA_WIDTH 1 /* AIF2RX4_ENA */ +#define ARIZONA_AIF2RX3_ENA 0x0004 /* AIF2RX3_ENA */ +#define ARIZONA_AIF2RX3_ENA_MASK 0x0004 /* AIF2RX3_ENA */ +#define ARIZONA_AIF2RX3_ENA_SHIFT 2 /* AIF2RX3_ENA */ +#define ARIZONA_AIF2RX3_ENA_WIDTH 1 /* AIF2RX3_ENA */ #define ARIZONA_AIF2RX2_ENA 0x0002 /* AIF2RX2_ENA */ #define ARIZONA_AIF2RX2_ENA_MASK 0x0002 /* AIF2RX2_ENA */ #define ARIZONA_AIF2RX2_ENA_SHIFT 1 /* AIF2RX2_ENA */ diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 6f05b17d1965..6977bf9f19a8 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -292,6 +292,10 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { "AIF1RX8", "AIF2RX1", "AIF2RX2", + "AIF2RX3", + "AIF2RX4", + "AIF2RX5", + "AIF2RX6", "AIF3RX1", "AIF3RX2", "SLIMRX1", @@ -395,6 +399,10 @@ int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = { 0x27, 0x28, /* AIF2RX1 */ 0x29, + 0x2a, + 0x2b, + 0x2c, + 0x2d, 0x30, /* AIF3RX1 */ 0x31, 0x38, /* SLIMRX1 */ diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 9e81b6392692..1f96672c7c1e 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -81,7 +81,7 @@ struct arizona_priv { unsigned int spk_ena_pending:1; }; -#define ARIZONA_NUM_MIXER_INPUTS 99 +#define ARIZONA_NUM_MIXER_INPUTS 103 extern const unsigned int arizona_mixer_tlv[]; extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS]; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index bbd64384ca1c..181de7df2c87 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -302,6 +302,10 @@ ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), @@ -361,6 +365,10 @@ ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE); ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE); @@ -561,11 +569,27 @@ SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_IN("SLIMRX1", NULL, 0, ARIZONA_SLIMBUS_RX_CHANNEL_ENABLE, @@ -703,6 +727,10 @@ ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"), ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"), ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), +ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"), +ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"), +ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"), +ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"), ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), @@ -764,6 +792,10 @@ SND_SOC_DAPM_OUTPUT("MICSUPP"), { name, "AIF1RX8", "AIF1RX8" }, \ { name, "AIF2RX1", "AIF2RX1" }, \ { name, "AIF2RX2", "AIF2RX2" }, \ + { name, "AIF2RX3", "AIF2RX3" }, \ + { name, "AIF2RX4", "AIF2RX4" }, \ + { name, "AIF2RX5", "AIF2RX5" }, \ + { name, "AIF2RX6", "AIF2RX6" }, \ { name, "AIF3RX1", "AIF3RX1" }, \ { name, "AIF3RX2", "AIF3RX2" }, \ { name, "SLIMRX1", "SLIMRX1" }, \ @@ -861,9 +893,17 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "AIF2 Capture", NULL, "AIF2TX1" }, { "AIF2 Capture", NULL, "AIF2TX2" }, + { "AIF2 Capture", NULL, "AIF2TX3" }, + { "AIF2 Capture", NULL, "AIF2TX4" }, + { "AIF2 Capture", NULL, "AIF2TX5" }, + { "AIF2 Capture", NULL, "AIF2TX6" }, { "AIF2RX1", NULL, "AIF2 Playback" }, { "AIF2RX2", NULL, "AIF2 Playback" }, + { "AIF2RX3", NULL, "AIF2 Playback" }, + { "AIF2RX4", NULL, "AIF2 Playback" }, + { "AIF2RX5", NULL, "AIF2 Playback" }, + { "AIF2RX6", NULL, "AIF2 Playback" }, { "AIF3 Capture", NULL, "AIF3TX1" }, { "AIF3 Capture", NULL, "AIF3TX2" }, @@ -947,6 +987,10 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"), ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), + ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"), + ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"), + ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"), + ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"), ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"), ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"), @@ -1067,14 +1111,14 @@ static struct snd_soc_dai_driver wm5110_dai[] = { .playback = { .stream_name = "AIF2 Playback", .channels_min = 1, - .channels_max = 2, + .channels_max = 6, .rates = WM5110_RATES, .formats = WM5110_FORMATS, }, .capture = { .stream_name = "AIF2 Capture", .channels_min = 1, - .channels_max = 2, + .channels_max = 6, .rates = WM5110_RATES, .formats = WM5110_FORMATS, }, -- cgit v1.2.3-59-g8ed1b From 3247343118daa73f2b94b7fa565425d1d9f9ac84 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 8 Nov 2013 18:52:21 +0100 Subject: uprobes: Add uprobe_task->dup_xol_work/dup_xol_addr uprobe_task->vaddr is a bit strange. The generic code uses it only to pass the additional argument to arch_uprobe_pre_xol(), and since it is always equal to instruction_pointer() this looks even more strange. And both utask->vaddr and and utask->autask have the same scope, they only have the meaning when the task executes the probed insn out-of-line, so it is safe to reuse both in UTASK_RUNNING state. This all means that logically ->vaddr belongs to arch_uprobe_task and we should probably move it there, arch_uprobe_pre_xol() can record instruction_pointer() itself. OTOH, it is also used by uprobe_copy_process() and dup_xol_work() for another purpose, this doesn't look clean and doesn't allow to move this member into arch_uprobe_task. This patch adds the union with 2 anonymous structs into uprobe_task. The first struct is autask + vaddr, this way we "almost" move vaddr into autask. The second struct has 2 new members for uprobe_copy_process() paths: ->dup_xol_addr which can be used instead ->vaddr, and ->dup_xol_work which can be used to avoid kmalloc() and simplify the code. Note that this union will likely have another member(s), we need something like "private_data_for_handlers" so that the tracing handlers could use it to communicate with call_fetch() methods. Signed-off-by: Oleg Nesterov Reviewed-by: Masami Hiramatsu Acked-by: Srikar Dronamraju --- include/linux/uprobes.h | 21 ++++++++++++++++----- kernel/events/uprobes.c | 16 ++++------------ 2 files changed, 20 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index 319eae70fe84..2225542624de 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h @@ -26,6 +26,7 @@ #include #include +#include struct vm_area_struct; struct mm_struct; @@ -72,14 +73,24 @@ enum uprobe_task_state { */ struct uprobe_task { enum uprobe_task_state state; - struct arch_uprobe_task autask; - struct return_instance *return_instances; - unsigned int depth; - struct uprobe *active_uprobe; + union { + struct { + struct arch_uprobe_task autask; + unsigned long vaddr; + }; + + struct { + struct callback_head dup_xol_work; + unsigned long dup_xol_addr; + }; + }; + struct uprobe *active_uprobe; unsigned long xol_vaddr; - unsigned long vaddr; + + struct return_instance *return_instances; + unsigned int depth; }; /* diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 24b7d6ca871b..df4ef0971266 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -1403,12 +1403,10 @@ static void uprobe_warn(struct task_struct *t, const char *msg) static void dup_xol_work(struct callback_head *work) { - kfree(work); - if (current->flags & PF_EXITING) return; - if (!__create_xol_area(current->utask->vaddr)) + if (!__create_xol_area(current->utask->dup_xol_addr)) uprobe_warn(current, "dup xol area"); } @@ -1419,7 +1417,6 @@ void uprobe_copy_process(struct task_struct *t, unsigned long flags) { struct uprobe_task *utask = current->utask; struct mm_struct *mm = current->mm; - struct callback_head *work; struct xol_area *area; t->utask = NULL; @@ -1441,14 +1438,9 @@ void uprobe_copy_process(struct task_struct *t, unsigned long flags) if (mm == t->mm) return; - /* TODO: move it into the union in uprobe_task */ - work = kmalloc(sizeof(*work), GFP_KERNEL); - if (!work) - return uprobe_warn(t, "dup xol area"); - - t->utask->vaddr = area->vaddr; - init_task_work(work, dup_xol_work); - task_work_add(t, work, true); + t->utask->dup_xol_addr = area->vaddr; + init_task_work(&t->utask->dup_xol_work, dup_xol_work); + task_work_add(t, &t->utask->dup_xol_work, true); } /* -- cgit v1.2.3-59-g8ed1b From c912dae60ae6f659455f239298110adc67a5f3e9 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 9 Nov 2013 19:49:39 +0100 Subject: uprobes: Cleanup !CONFIG_UPROBES decls, unexport xol_area 1. Don't include asm/uprobes.h unconditionally, we only need it if CONFIG_UPROBES. 2. Move the definition of "struct xol_area" into uprobes.c. Perhaps we should simply kill struct uprobes_state, it buys nothing. 3. Kill the dummy definition of uprobe_get_swbp_addr(), nobody except handle_swbp() needs it. 4. Purely cosmetic, but move the decl of uprobe_get_swbp_addr() up, close to other __weak helpers. Signed-off-by: Oleg Nesterov Acked-by: Srikar Dronamraju --- include/linux/uprobes.h | 31 ++++--------------------------- kernel/events/uprobes.c | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 27 deletions(-) (limited to 'include/linux') diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index 2225542624de..e32251e00e62 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h @@ -33,10 +33,6 @@ struct mm_struct; struct inode; struct notifier_block; -#ifdef CONFIG_ARCH_SUPPORTS_UPROBES -# include -#endif - #define UPROBE_HANDLER_REMOVE 1 #define UPROBE_HANDLER_MASK 1 @@ -61,6 +57,8 @@ struct uprobe_consumer { }; #ifdef CONFIG_UPROBES +#include + enum uprobe_task_state { UTASK_RUNNING, UTASK_SSTEP, @@ -93,24 +91,7 @@ struct uprobe_task { unsigned int depth; }; -/* - * On a breakpoint hit, thread contests for a slot. It frees the - * slot after singlestep. Currently a fixed number of slots are - * allocated. - */ -struct xol_area { - wait_queue_head_t wq; /* if all slots are busy */ - atomic_t slot_count; /* number of in-use slots */ - unsigned long *bitmap; /* 0 = free slot */ - struct page *page; - - /* - * We keep the vma's vm_start rather than a pointer to the vma - * itself. The probed process or a naughty kernel module could make - * the vma go away, and we must handle that reasonably gracefully. - */ - unsigned long vaddr; /* Page(s) of instruction slots */ -}; +struct xol_area; struct uprobes_state { struct xol_area *xol_area; @@ -120,6 +101,7 @@ extern int __weak set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsign extern int __weak set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); extern bool __weak is_swbp_insn(uprobe_opcode_t *insn); extern bool __weak is_trap_insn(uprobe_opcode_t *insn); +extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); extern int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t); extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool); @@ -131,7 +113,6 @@ extern void uprobe_end_dup_mmap(void); extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm); extern void uprobe_free_utask(struct task_struct *t); extern void uprobe_copy_process(struct task_struct *t, unsigned long flags); -extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); extern int uprobe_post_sstep_notifier(struct pt_regs *regs); extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); extern void uprobe_notify_resume(struct pt_regs *regs); @@ -187,10 +168,6 @@ static inline bool uprobe_deny_signal(void) { return false; } -static inline unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) -{ - return 0; -} static inline void uprobe_free_utask(struct task_struct *t) { } diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 445962a72498..51a7f535ff96 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -85,6 +85,25 @@ struct return_instance { struct return_instance *next; /* keep as stack */ }; +/* + * On a breakpoint hit, thread contests for a slot. It frees the + * slot after singlestep. Currently a fixed number of slots are + * allocated. + */ +struct xol_area { + wait_queue_head_t wq; /* if all slots are busy */ + atomic_t slot_count; /* number of in-use slots */ + unsigned long *bitmap; /* 0 = free slot */ + struct page *page; + + /* + * We keep the vma's vm_start rather than a pointer to the vma + * itself. The probed process or a naughty kernel module could make + * the vma go away, and we must handle that reasonably gracefully. + */ + unsigned long vaddr; /* Page(s) of instruction slots */ +}; + /* * valid_vma: Verify if the specified vma is an executable vma * Relax restrictions while unregistering: vm_flags might have -- cgit v1.2.3-59-g8ed1b From 254dc326dbfd23c2678fafad1b84fc0e42ac4374 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 19 Nov 2013 16:04:03 +0000 Subject: ASoC: wm5110: Expose input high pass filter controls Acked-by: Mark Brown Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm5110-tables.c | 4 ++++ include/linux/mfd/arizona/registers.h | 37 +++++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.c | 10 ++++++++++ sound/soc/codecs/arizona.h | 1 + sound/soc/codecs/wm5110.c | 19 ++++++++++++++++++ 5 files changed, 71 insertions(+) (limited to 'include/linux') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 4430404471c0..3b079f6b021e 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -518,6 +518,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000300, 0x0000 }, /* R768 - Input Enables */ { 0x00000308, 0x0000 }, /* R776 - Input Rate */ { 0x00000309, 0x0022 }, /* R777 - Input Volume Ramp */ + { 0x0000030C, 0x0002 }, /* R780 - HPF Control */ { 0x00000310, 0x2080 }, /* R784 - IN1L Control */ { 0x00000311, 0x0180 }, /* R785 - ADC Digital Volume 1L */ { 0x00000312, 0x0000 }, /* R786 - DMIC1L Control */ @@ -539,6 +540,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000328, 0x2000 }, /* R808 - IN4L Control */ { 0x00000329, 0x0180 }, /* R809 - ADC Digital Volume 4L */ { 0x0000032A, 0x0000 }, /* R810 - DMIC4L Control */ + { 0x0000032C, 0x0000 }, /* R812 - IN4R Control */ { 0x0000032D, 0x0180 }, /* R813 - ADC Digital Volume 4R */ { 0x0000032E, 0x0000 }, /* R814 - DMIC4R Control */ { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */ @@ -1512,6 +1514,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_INPUT_ENABLES_STATUS: case ARIZONA_INPUT_RATE: case ARIZONA_INPUT_VOLUME_RAMP: + case ARIZONA_HPF_CONTROL: case ARIZONA_IN1L_CONTROL: case ARIZONA_ADC_DIGITAL_VOLUME_1L: case ARIZONA_DMIC1L_CONTROL: @@ -1533,6 +1536,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_IN4L_CONTROL: case ARIZONA_ADC_DIGITAL_VOLUME_4L: case ARIZONA_DMIC4L_CONTROL: + case ARIZONA_IN4R_CONTROL: case ARIZONA_ADC_DIGITAL_VOLUME_4R: case ARIZONA_DMIC4R_CONTROL: case ARIZONA_OUTPUT_ENABLES_1: diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 4706d3d46e56..cdf1f5acbe53 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -139,6 +139,7 @@ #define ARIZONA_INPUT_ENABLES_STATUS 0x301 #define ARIZONA_INPUT_RATE 0x308 #define ARIZONA_INPUT_VOLUME_RAMP 0x309 +#define ARIZONA_HPF_CONTROL 0x30C #define ARIZONA_IN1L_CONTROL 0x310 #define ARIZONA_ADC_DIGITAL_VOLUME_1L 0x311 #define ARIZONA_DMIC1L_CONTROL 0x312 @@ -160,6 +161,7 @@ #define ARIZONA_IN4L_CONTROL 0x328 #define ARIZONA_ADC_DIGITAL_VOLUME_4L 0x329 #define ARIZONA_DMIC4L_CONTROL 0x32A +#define ARIZONA_IN4R_CONTROL 0x32C #define ARIZONA_ADC_DIGITAL_VOLUME_4R 0x32D #define ARIZONA_DMIC4R_CONTROL 0x32E #define ARIZONA_OUTPUT_ENABLES_1 0x400 @@ -2292,9 +2294,19 @@ #define ARIZONA_IN_VI_RAMP_SHIFT 0 /* IN_VI_RAMP - [2:0] */ #define ARIZONA_IN_VI_RAMP_WIDTH 3 /* IN_VI_RAMP - [2:0] */ +/* + * R780 (0x30C) - HPF Control + */ +#define ARIZONA_IN_HPF_CUT_MASK 0x0007 /* IN_HPF_CUT [2:0] */ +#define ARIZONA_IN_HPF_CUT_SHIFT 0 /* IN_HPF_CUT [2:0] */ +#define ARIZONA_IN_HPF_CUT_WIDTH 3 /* IN_HPF_CUT [2:0] */ + /* * R784 (0x310) - IN1L Control */ +#define ARIZONA_IN1L_HPF_MASK 0x8000 /* IN1L_HPF - [15] */ +#define ARIZONA_IN1L_HPF_SHIFT 15 /* IN1L_HPF - [15] */ +#define ARIZONA_IN1L_HPF_WIDTH 1 /* IN1L_HPF - [15] */ #define ARIZONA_IN1_OSR_MASK 0x6000 /* IN1_OSR - [14:13] */ #define ARIZONA_IN1_OSR_SHIFT 13 /* IN1_OSR - [14:13] */ #define ARIZONA_IN1_OSR_WIDTH 2 /* IN1_OSR - [14:13] */ @@ -2333,6 +2345,9 @@ /* * R788 (0x314) - IN1R Control */ +#define ARIZONA_IN1R_HPF_MASK 0x8000 /* IN1R_HPF - [15] */ +#define ARIZONA_IN1R_HPF_SHIFT 15 /* IN1R_HPF - [15] */ +#define ARIZONA_IN1R_HPF_WIDTH 1 /* IN1R_HPF - [15] */ #define ARIZONA_IN1R_PGA_VOL_MASK 0x00FE /* IN1R_PGA_VOL - [7:1] */ #define ARIZONA_IN1R_PGA_VOL_SHIFT 1 /* IN1R_PGA_VOL - [7:1] */ #define ARIZONA_IN1R_PGA_VOL_WIDTH 7 /* IN1R_PGA_VOL - [7:1] */ @@ -2362,6 +2377,9 @@ /* * R792 (0x318) - IN2L Control */ +#define ARIZONA_IN2L_HPF_MASK 0x8000 /* IN2L_HPF - [15] */ +#define ARIZONA_IN2L_HPF_SHIFT 15 /* IN2L_HPF - [15] */ +#define ARIZONA_IN2L_HPF_WIDTH 1 /* IN2L_HPF - [15] */ #define ARIZONA_IN2_OSR_MASK 0x6000 /* IN2_OSR - [14:13] */ #define ARIZONA_IN2_OSR_SHIFT 13 /* IN2_OSR - [14:13] */ #define ARIZONA_IN2_OSR_WIDTH 2 /* IN2_OSR - [14:13] */ @@ -2400,6 +2418,9 @@ /* * R796 (0x31C) - IN2R Control */ +#define ARIZONA_IN2R_HPF_MASK 0x8000 /* IN2R_HPF - [15] */ +#define ARIZONA_IN2R_HPF_SHIFT 15 /* IN2R_HPF - [15] */ +#define ARIZONA_IN2R_HPF_WIDTH 1 /* IN2R_HPF - [15] */ #define ARIZONA_IN2R_PGA_VOL_MASK 0x00FE /* IN2R_PGA_VOL - [7:1] */ #define ARIZONA_IN2R_PGA_VOL_SHIFT 1 /* IN2R_PGA_VOL - [7:1] */ #define ARIZONA_IN2R_PGA_VOL_WIDTH 7 /* IN2R_PGA_VOL - [7:1] */ @@ -2429,6 +2450,9 @@ /* * R800 (0x320) - IN3L Control */ +#define ARIZONA_IN3L_HPF_MASK 0x8000 /* IN3L_HPF - [15] */ +#define ARIZONA_IN3L_HPF_SHIFT 15 /* IN3L_HPF - [15] */ +#define ARIZONA_IN3L_HPF_WIDTH 1 /* IN3L_HPF - [15] */ #define ARIZONA_IN3_OSR_MASK 0x6000 /* IN3_OSR - [14:13] */ #define ARIZONA_IN3_OSR_SHIFT 13 /* IN3_OSR - [14:13] */ #define ARIZONA_IN3_OSR_WIDTH 2 /* IN3_OSR - [14:13] */ @@ -2467,6 +2491,9 @@ /* * R804 (0x324) - IN3R Control */ +#define ARIZONA_IN3R_HPF_MASK 0x8000 /* IN3R_HPF - [15] */ +#define ARIZONA_IN3R_HPF_SHIFT 15 /* IN3R_HPF - [15] */ +#define ARIZONA_IN3R_HPF_WIDTH 1 /* IN3R_HPF - [15] */ #define ARIZONA_IN3R_PGA_VOL_MASK 0x00FE /* IN3R_PGA_VOL - [7:1] */ #define ARIZONA_IN3R_PGA_VOL_SHIFT 1 /* IN3R_PGA_VOL - [7:1] */ #define ARIZONA_IN3R_PGA_VOL_WIDTH 7 /* IN3R_PGA_VOL - [7:1] */ @@ -2496,6 +2523,9 @@ /* * R808 (0x328) - IN4 Control */ +#define ARIZONA_IN4L_HPF_MASK 0x8000 /* IN4L_HPF - [15] */ +#define ARIZONA_IN4L_HPF_SHIFT 15 /* IN4L_HPF - [15] */ +#define ARIZONA_IN4L_HPF_WIDTH 1 /* IN4L_HPF - [15] */ #define ARIZONA_IN4_OSR_MASK 0x6000 /* IN4_OSR - [14:13] */ #define ARIZONA_IN4_OSR_SHIFT 13 /* IN4_OSR - [14:13] */ #define ARIZONA_IN4_OSR_WIDTH 2 /* IN4_OSR - [14:13] */ @@ -2525,6 +2555,13 @@ #define ARIZONA_IN4L_DMIC_DLY_SHIFT 0 /* IN4L_DMIC_DLY - [5:0] */ #define ARIZONA_IN4L_DMIC_DLY_WIDTH 6 /* IN4L_DMIC_DLY - [5:0] */ +/* + * R812 (0x32C) - IN4R Control + */ +#define ARIZONA_IN4R_HPF_MASK 0x8000 /* IN4R_HPF - [15] */ +#define ARIZONA_IN4R_HPF_SHIFT 15 /* IN4R_HPF - [15] */ +#define ARIZONA_IN4R_HPF_WIDTH 1 /* IN4R_HPF - [15] */ + /* * R813 (0x32D) - ADC Digital Volume 4R */ diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 657808ba1418..708326265a37 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -560,6 +560,16 @@ const struct soc_enum arizona_ng_hold = 4, arizona_ng_hold_text); EXPORT_SYMBOL_GPL(arizona_ng_hold); +static const char * const arizona_in_hpf_cut_text[] = { + "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz" +}; + +const struct soc_enum arizona_in_hpf_cut_enum = + SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT, + ARRAY_SIZE(arizona_in_hpf_cut_text), + arizona_in_hpf_cut_text); +EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); + static const char * const arizona_in_dmic_osr_text[] = { "1.536MHz", "3.072MHz", "6.144MHz", }; diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 9e81b6392692..f8e63865a1c5 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -199,6 +199,7 @@ extern const struct soc_enum arizona_lhpf3_mode; extern const struct soc_enum arizona_lhpf4_mode; extern const struct soc_enum arizona_ng_hold; +extern const struct soc_enum arizona_in_hpf_cut_enum; extern const struct soc_enum arizona_in_dmic_osr[]; extern int arizona_in_ev(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index bbd64384ca1c..ea18e88e0a07 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -76,6 +76,25 @@ SOC_SINGLE_RANGE_TLV("IN3L Volume", ARIZONA_IN3L_CONTROL, SOC_SINGLE_RANGE_TLV("IN3R Volume", ARIZONA_IN3R_CONTROL, ARIZONA_IN3R_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), +SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum), + +SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL, + ARIZONA_IN1L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL, + ARIZONA_IN1R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL, + ARIZONA_IN2L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL, + ARIZONA_IN2R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN3L HPF Switch", ARIZONA_IN3L_CONTROL, + ARIZONA_IN3L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN3R HPF Switch", ARIZONA_IN3R_CONTROL, + ARIZONA_IN3R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN4L HPF Switch", ARIZONA_IN4L_CONTROL, + ARIZONA_IN4L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN4R HPF Switch", ARIZONA_IN4R_CONTROL, + ARIZONA_IN4R_HPF_SHIFT, 1, 0), + SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R, -- cgit v1.2.3-59-g8ed1b From 79bd9814e5ec9a288d6599f53aeac0b548fdfe52 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 22 Nov 2013 18:20:42 -0500 Subject: cgroup, memcg: move cgroup_event implementation to memcg cgroup_event is way over-designed and tries to build a generic flexible event mechanism into cgroup - fully customizable event specification for each user of the interface. This is utterly unnecessary and overboard especially in the light of the planned unified hierarchy as there's gonna be single agent. Simply generating events at fixed points, or if that's too restrictive, configureable cadence or single set of configureable points should be enough. Thankfully, memcg is the only user and gets to keep it. Replacing it with something simpler on sane_behavior is strongly recommended. This patch moves cgroup_event and "cgroup.event_control" implementation to mm/memcontrol.c. Clearing of events on cgroup destruction is moved from cgroup_destroy_locked() to mem_cgroup_css_offline(), which shouldn't make any noticeable difference. cgroup_css() and __file_cft() are exported to enable the move; however, this will soon be reverted once the event code is updated to be memcg specific. Note that "cgroup.event_control" will now exist only on the hierarchy with memcg attached to it. While this change is visible to userland, it is unlikely to be noticeable as the file has never been meaningful outside memcg. Aside from the above change, this is pure code relocation. v2: Per Li Zefan's comments, init/Kconfig updated accordingly and poll.h inclusion moved from cgroup.c to memcontrol.c. Signed-off-by: Tejun Heo Acked-by: Li Zefan Acked-by: Kirill A. Shutemov Acked-by: Michal Hocko Cc: Johannes Weiner Cc: Balbir Singh --- include/linux/cgroup.h | 5 + init/Kconfig | 3 +- kernel/cgroup.c | 253 +------------------------------------------------ mm/memcontrol.c | 248 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 257 insertions(+), 252 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 3561d305b1e0..40c2427806c9 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -907,6 +907,11 @@ unsigned short css_id(struct cgroup_subsys_state *css); struct cgroup_subsys_state *css_from_dir(struct dentry *dentry, struct cgroup_subsys *ss); +/* XXX: temporary */ +struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, + struct cgroup_subsys *ss); +struct cftype *__file_cft(struct file *file); + #else /* !CONFIG_CGROUPS */ static inline int cgroup_init_early(void) { return 0; } diff --git a/init/Kconfig b/init/Kconfig index 3ecd8a1178f1..3ca5b8110b0c 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -861,7 +861,6 @@ config NUMA_BALANCING menuconfig CGROUPS boolean "Control Group support" - depends on EVENTFD help This option adds support for grouping sets of processes together, for use with process control subsystems such as Cpusets, CFS, memory @@ -928,6 +927,7 @@ config MEMCG bool "Memory Resource Controller for Control Groups" depends on RESOURCE_COUNTERS select MM_OWNER + select EVENTFD help Provides a memory resource controller that manages both anonymous memory and page cache. (See Documentation/cgroups/memory.txt) @@ -1167,7 +1167,6 @@ config UIDGID_STRICT_TYPE_CHECKS config SCHED_AUTOGROUP bool "Automatic process group scheduling" - select EVENTFD select CGROUPS select CGROUP_SCHED select FAIR_GROUP_SCHED diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 8bd9cfdc70d7..4bccaa7dda35 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -56,11 +56,8 @@ #include #include #include /* TODO: replace with more sophisticated array */ -#include -#include #include /* used in cgroup_attach_task */ #include -#include #include @@ -156,36 +153,6 @@ struct css_id { unsigned short stack[0]; /* Array of Length (depth+1) */ }; -/* - * cgroup_event represents events which userspace want to receive. - */ -struct cgroup_event { - /* - * css which the event belongs to. - */ - struct cgroup_subsys_state *css; - /* - * Control file which the event associated. - */ - struct cftype *cft; - /* - * eventfd to signal userspace about the event. - */ - struct eventfd_ctx *eventfd; - /* - * Each of these stored in a list by the cgroup. - */ - struct list_head list; - /* - * All fields below needed to unregister event when - * userspace closes eventfd. - */ - poll_table pt; - wait_queue_head_t *wqh; - wait_queue_t wait; - struct work_struct remove; -}; - /* The list of hierarchy roots */ static LIST_HEAD(cgroup_roots); @@ -235,8 +202,8 @@ static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], * keep accessing it outside the said locks. This function may return * %NULL if @cgrp doesn't have @subsys_id enabled. */ -static struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, - struct cgroup_subsys *ss) +struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, + struct cgroup_subsys *ss) { if (ss) return rcu_dereference_check(cgrp->subsys[ss->subsys_id], @@ -2663,7 +2630,7 @@ static const struct inode_operations cgroup_dir_inode_operations = { /* * Check if a file is a control file */ -static inline struct cftype *__file_cft(struct file *file) +struct cftype *__file_cft(struct file *file) { if (file_inode(file)->i_fop != &cgroup_file_operations) return ERR_PTR(-EINVAL); @@ -3949,202 +3916,6 @@ static void cgroup_dput(struct cgroup *cgrp) deactivate_super(sb); } -/* - * Unregister event and free resources. - * - * Gets called from workqueue. - */ -static void cgroup_event_remove(struct work_struct *work) -{ - struct cgroup_event *event = container_of(work, struct cgroup_event, - remove); - struct cgroup_subsys_state *css = event->css; - - remove_wait_queue(event->wqh, &event->wait); - - event->cft->unregister_event(css, event->cft, event->eventfd); - - /* Notify userspace the event is going away. */ - eventfd_signal(event->eventfd, 1); - - eventfd_ctx_put(event->eventfd); - kfree(event); - css_put(css); -} - -/* - * Gets called on POLLHUP on eventfd when user closes it. - * - * Called with wqh->lock held and interrupts disabled. - */ -static int cgroup_event_wake(wait_queue_t *wait, unsigned mode, - int sync, void *key) -{ - struct cgroup_event *event = container_of(wait, - struct cgroup_event, wait); - struct cgroup *cgrp = event->css->cgroup; - unsigned long flags = (unsigned long)key; - - if (flags & POLLHUP) { - /* - * If the event has been detached at cgroup removal, we - * can simply return knowing the other side will cleanup - * for us. - * - * We can't race against event freeing since the other - * side will require wqh->lock via remove_wait_queue(), - * which we hold. - */ - spin_lock(&cgrp->event_list_lock); - if (!list_empty(&event->list)) { - list_del_init(&event->list); - /* - * We are in atomic context, but cgroup_event_remove() - * may sleep, so we have to call it in workqueue. - */ - schedule_work(&event->remove); - } - spin_unlock(&cgrp->event_list_lock); - } - - return 0; -} - -static void cgroup_event_ptable_queue_proc(struct file *file, - wait_queue_head_t *wqh, poll_table *pt) -{ - struct cgroup_event *event = container_of(pt, - struct cgroup_event, pt); - - event->wqh = wqh; - add_wait_queue(wqh, &event->wait); -} - -/* - * Parse input and register new cgroup event handler. - * - * Input must be in format ' '. - * Interpretation of args is defined by control file implementation. - */ -static int cgroup_write_event_control(struct cgroup_subsys_state *dummy_css, - struct cftype *cft, const char *buffer) -{ - struct cgroup *cgrp = dummy_css->cgroup; - struct cgroup_event *event; - struct cgroup_subsys_state *cfile_css; - unsigned int efd, cfd; - struct fd efile; - struct fd cfile; - char *endp; - int ret; - - efd = simple_strtoul(buffer, &endp, 10); - if (*endp != ' ') - return -EINVAL; - buffer = endp + 1; - - cfd = simple_strtoul(buffer, &endp, 10); - if ((*endp != ' ') && (*endp != '\0')) - return -EINVAL; - buffer = endp + 1; - - event = kzalloc(sizeof(*event), GFP_KERNEL); - if (!event) - return -ENOMEM; - - INIT_LIST_HEAD(&event->list); - init_poll_funcptr(&event->pt, cgroup_event_ptable_queue_proc); - init_waitqueue_func_entry(&event->wait, cgroup_event_wake); - INIT_WORK(&event->remove, cgroup_event_remove); - - efile = fdget(efd); - if (!efile.file) { - ret = -EBADF; - goto out_kfree; - } - - event->eventfd = eventfd_ctx_fileget(efile.file); - if (IS_ERR(event->eventfd)) { - ret = PTR_ERR(event->eventfd); - goto out_put_efile; - } - - cfile = fdget(cfd); - if (!cfile.file) { - ret = -EBADF; - goto out_put_eventfd; - } - - /* the process need read permission on control file */ - /* AV: shouldn't we check that it's been opened for read instead? */ - ret = inode_permission(file_inode(cfile.file), MAY_READ); - if (ret < 0) - goto out_put_cfile; - - event->cft = __file_cft(cfile.file); - if (IS_ERR(event->cft)) { - ret = PTR_ERR(event->cft); - goto out_put_cfile; - } - - if (!event->cft->ss) { - ret = -EBADF; - goto out_put_cfile; - } - - /* - * Determine the css of @cfile, verify it belongs to the same - * cgroup as cgroup.event_control, and associate @event with it. - * Remaining events are automatically removed on cgroup destruction - * but the removal is asynchronous, so take an extra ref. - */ - rcu_read_lock(); - - ret = -EINVAL; - event->css = cgroup_css(cgrp, event->cft->ss); - cfile_css = css_from_dir(cfile.file->f_dentry->d_parent, event->cft->ss); - if (event->css && event->css == cfile_css && css_tryget(event->css)) - ret = 0; - - rcu_read_unlock(); - if (ret) - goto out_put_cfile; - - if (!event->cft->register_event || !event->cft->unregister_event) { - ret = -EINVAL; - goto out_put_css; - } - - ret = event->cft->register_event(event->css, event->cft, - event->eventfd, buffer); - if (ret) - goto out_put_css; - - efile.file->f_op->poll(efile.file, &event->pt); - - spin_lock(&cgrp->event_list_lock); - list_add(&event->list, &cgrp->event_list); - spin_unlock(&cgrp->event_list_lock); - - fdput(cfile); - fdput(efile); - - return 0; - -out_put_css: - css_put(event->css); -out_put_cfile: - fdput(cfile); -out_put_eventfd: - eventfd_ctx_put(event->eventfd); -out_put_efile: - fdput(efile); -out_kfree: - kfree(event); - - return ret; -} - static u64 cgroup_clone_children_read(struct cgroup_subsys_state *css, struct cftype *cft) { @@ -4169,11 +3940,6 @@ static struct cftype cgroup_base_files[] = { .release = cgroup_pidlist_release, .mode = S_IRUGO | S_IWUSR, }, - { - .name = "cgroup.event_control", - .write_string = cgroup_write_event_control, - .mode = S_IWUGO, - }, { .name = "cgroup.clone_children", .flags = CFTYPE_INSANE, @@ -4666,7 +4432,6 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) __releases(&cgroup_mutex) __acquires(&cgroup_mutex) { struct dentry *d = cgrp->dentry; - struct cgroup_event *event, *tmp; struct cgroup_subsys *ss; struct cgroup *child; bool empty; @@ -4741,18 +4506,6 @@ static int cgroup_destroy_locked(struct cgroup *cgrp) dget(d); cgroup_d_remove_dir(d); - /* - * Unregister events and notify userspace. - * Notify userspace about cgroup removing only after rmdir of cgroup - * directory to avoid race between userspace and kernelspace. - */ - spin_lock(&cgrp->event_list_lock); - list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) { - list_del_init(&event->list); - schedule_work(&event->remove); - } - spin_unlock(&cgrp->event_list_lock); - return 0; }; diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 13b9d0f221b8..02dae3292668 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ #include #include #include +#include #include "internal.h" #include #include @@ -226,6 +228,36 @@ struct mem_cgroup_eventfd_list { struct eventfd_ctx *eventfd; }; +/* + * cgroup_event represents events which userspace want to receive. + */ +struct cgroup_event { + /* + * css which the event belongs to. + */ + struct cgroup_subsys_state *css; + /* + * Control file which the event associated. + */ + struct cftype *cft; + /* + * eventfd to signal userspace about the event. + */ + struct eventfd_ctx *eventfd; + /* + * Each of these stored in a list by the cgroup. + */ + struct list_head list; + /* + * All fields below needed to unregister event when + * userspace closes eventfd. + */ + poll_table pt; + wait_queue_head_t *wqh; + wait_queue_t wait; + struct work_struct remove; +}; + static void mem_cgroup_threshold(struct mem_cgroup *memcg); static void mem_cgroup_oom_notify(struct mem_cgroup *memcg); @@ -5947,6 +5979,202 @@ static void kmem_cgroup_css_offline(struct mem_cgroup *memcg) } #endif +/* + * Unregister event and free resources. + * + * Gets called from workqueue. + */ +static void cgroup_event_remove(struct work_struct *work) +{ + struct cgroup_event *event = container_of(work, struct cgroup_event, + remove); + struct cgroup_subsys_state *css = event->css; + + remove_wait_queue(event->wqh, &event->wait); + + event->cft->unregister_event(css, event->cft, event->eventfd); + + /* Notify userspace the event is going away. */ + eventfd_signal(event->eventfd, 1); + + eventfd_ctx_put(event->eventfd); + kfree(event); + css_put(css); +} + +/* + * Gets called on POLLHUP on eventfd when user closes it. + * + * Called with wqh->lock held and interrupts disabled. + */ +static int cgroup_event_wake(wait_queue_t *wait, unsigned mode, + int sync, void *key) +{ + struct cgroup_event *event = container_of(wait, + struct cgroup_event, wait); + struct cgroup *cgrp = event->css->cgroup; + unsigned long flags = (unsigned long)key; + + if (flags & POLLHUP) { + /* + * If the event has been detached at cgroup removal, we + * can simply return knowing the other side will cleanup + * for us. + * + * We can't race against event freeing since the other + * side will require wqh->lock via remove_wait_queue(), + * which we hold. + */ + spin_lock(&cgrp->event_list_lock); + if (!list_empty(&event->list)) { + list_del_init(&event->list); + /* + * We are in atomic context, but cgroup_event_remove() + * may sleep, so we have to call it in workqueue. + */ + schedule_work(&event->remove); + } + spin_unlock(&cgrp->event_list_lock); + } + + return 0; +} + +static void cgroup_event_ptable_queue_proc(struct file *file, + wait_queue_head_t *wqh, poll_table *pt) +{ + struct cgroup_event *event = container_of(pt, + struct cgroup_event, pt); + + event->wqh = wqh; + add_wait_queue(wqh, &event->wait); +} + +/* + * Parse input and register new cgroup event handler. + * + * Input must be in format ' '. + * Interpretation of args is defined by control file implementation. + */ +static int cgroup_write_event_control(struct cgroup_subsys_state *dummy_css, + struct cftype *cft, const char *buffer) +{ + struct cgroup *cgrp = dummy_css->cgroup; + struct cgroup_event *event; + struct cgroup_subsys_state *cfile_css; + unsigned int efd, cfd; + struct fd efile; + struct fd cfile; + char *endp; + int ret; + + efd = simple_strtoul(buffer, &endp, 10); + if (*endp != ' ') + return -EINVAL; + buffer = endp + 1; + + cfd = simple_strtoul(buffer, &endp, 10); + if ((*endp != ' ') && (*endp != '\0')) + return -EINVAL; + buffer = endp + 1; + + event = kzalloc(sizeof(*event), GFP_KERNEL); + if (!event) + return -ENOMEM; + + INIT_LIST_HEAD(&event->list); + init_poll_funcptr(&event->pt, cgroup_event_ptable_queue_proc); + init_waitqueue_func_entry(&event->wait, cgroup_event_wake); + INIT_WORK(&event->remove, cgroup_event_remove); + + efile = fdget(efd); + if (!efile.file) { + ret = -EBADF; + goto out_kfree; + } + + event->eventfd = eventfd_ctx_fileget(efile.file); + if (IS_ERR(event->eventfd)) { + ret = PTR_ERR(event->eventfd); + goto out_put_efile; + } + + cfile = fdget(cfd); + if (!cfile.file) { + ret = -EBADF; + goto out_put_eventfd; + } + + /* the process need read permission on control file */ + /* AV: shouldn't we check that it's been opened for read instead? */ + ret = inode_permission(file_inode(cfile.file), MAY_READ); + if (ret < 0) + goto out_put_cfile; + + event->cft = __file_cft(cfile.file); + if (IS_ERR(event->cft)) { + ret = PTR_ERR(event->cft); + goto out_put_cfile; + } + + if (!event->cft->ss) { + ret = -EBADF; + goto out_put_cfile; + } + + /* + * Determine the css of @cfile, verify it belongs to the same + * cgroup as cgroup.event_control, and associate @event with it. + * Remaining events are automatically removed on cgroup destruction + * but the removal is asynchronous, so take an extra ref. + */ + rcu_read_lock(); + + ret = -EINVAL; + event->css = cgroup_css(cgrp, event->cft->ss); + cfile_css = css_from_dir(cfile.file->f_dentry->d_parent, event->cft->ss); + if (event->css && event->css == cfile_css && css_tryget(event->css)) + ret = 0; + + rcu_read_unlock(); + if (ret) + goto out_put_cfile; + + if (!event->cft->register_event || !event->cft->unregister_event) { + ret = -EINVAL; + goto out_put_css; + } + + ret = event->cft->register_event(event->css, event->cft, + event->eventfd, buffer); + if (ret) + goto out_put_css; + + efile.file->f_op->poll(efile.file, &event->pt); + + spin_lock(&cgrp->event_list_lock); + list_add(&event->list, &cgrp->event_list); + spin_unlock(&cgrp->event_list_lock); + + fdput(cfile); + fdput(efile); + + return 0; + +out_put_css: + css_put(event->css); +out_put_cfile: + fdput(cfile); +out_put_eventfd: + eventfd_ctx_put(event->eventfd); +out_put_efile: + fdput(efile); +out_kfree: + kfree(event); + + return ret; +} + static struct cftype mem_cgroup_files[] = { { .name = "usage_in_bytes", @@ -5993,6 +6221,12 @@ static struct cftype mem_cgroup_files[] = { .write_u64 = mem_cgroup_hierarchy_write, .read_u64 = mem_cgroup_hierarchy_read, }, + { + .name = "cgroup.event_control", + .write_string = cgroup_write_event_control, + .flags = CFTYPE_NO_PREFIX, + .mode = S_IWUGO, + }, { .name = "swappiness", .read_u64 = mem_cgroup_swappiness_read, @@ -6326,6 +6560,20 @@ static void mem_cgroup_invalidate_reclaim_iterators(struct mem_cgroup *memcg) static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); + struct cgroup *cgrp = css->cgroup; + struct cgroup_event *event, *tmp; + + /* + * Unregister events and notify userspace. + * Notify userspace about cgroup removing only after rmdir of cgroup + * directory to avoid race between userspace and kernelspace. + */ + spin_lock(&cgrp->event_list_lock); + list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) { + list_del_init(&event->list); + schedule_work(&event->remove); + } + spin_unlock(&cgrp->event_list_lock); kmem_cgroup_css_offline(memcg); -- cgit v1.2.3-59-g8ed1b From fba94807837850e211f8975e1970e23e7804ff4d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 22 Nov 2013 18:20:43 -0500 Subject: cgroup, memcg: move cgroup->event_list[_lock] and event callbacks into memcg cgroup_event is being moved from cgroup core to memcg and the implementation is already moved by the previous patch. This patch moves the data fields and callbacks. * cgroup->event_list[_lock] are moved to mem_cgroup. * cftype->[un]register_event() are moved to cgroup_event. This makes it impossible for individual cftype definitions to specify their event callbacks. This is worked around by simply hard-coding filename to event callback mapping in cgroup_write_event_control(). This is awkward and inflexible, which is actually desirable given that we don't want to grow more usages of this feature. * eventfd_ctx declaration is removed from cgroup.h, which makes vmpressure.h miss eventfd_ctx declaration. Include eventfd.h from vmpressure.h. v2: Use file name from dentry instead of cftype. This will allow removing all cftype handling in the function. Signed-off-by: Tejun Heo Acked-by: Li Zefan Acked-by: Kirill A. Shutemov Acked-by: Michal Hocko Cc: Johannes Weiner Cc: Balbir Singh --- include/linux/cgroup.h | 24 ------------- include/linux/vmpressure.h | 1 + kernel/cgroup.c | 2 -- mm/memcontrol.c | 87 ++++++++++++++++++++++++++++++++-------------- 4 files changed, 61 insertions(+), 53 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 40c2427806c9..612adc5b87c5 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -29,7 +29,6 @@ struct cgroup_subsys; struct inode; struct cgroup; struct css_id; -struct eventfd_ctx; extern int cgroup_init_early(void); extern int cgroup_init(void); @@ -239,10 +238,6 @@ struct cgroup { struct rcu_head rcu_head; struct work_struct destroy_work; - /* List of events which userspace want to receive */ - struct list_head event_list; - spinlock_t event_list_lock; - /* directory xattrs */ struct simple_xattrs xattrs; }; @@ -506,25 +501,6 @@ struct cftype { int (*trigger)(struct cgroup_subsys_state *css, unsigned int event); int (*release)(struct inode *inode, struct file *file); - - /* - * register_event() callback will be used to add new userspace - * waiter for changes related to the cftype. Implement it if - * you want to provide this functionality. Use eventfd_signal() - * on eventfd to send notification to userspace. - */ - int (*register_event)(struct cgroup_subsys_state *css, - struct cftype *cft, struct eventfd_ctx *eventfd, - const char *args); - /* - * unregister_event() callback will be called when userspace - * closes the eventfd or on cgroup removing. - * This callback must be implemented, if you want provide - * notification functionality. - */ - void (*unregister_event)(struct cgroup_subsys_state *css, - struct cftype *cft, - struct eventfd_ctx *eventfd); }; /* diff --git a/include/linux/vmpressure.h b/include/linux/vmpressure.h index 3f3788d49362..9dd1914f1a6c 100644 --- a/include/linux/vmpressure.h +++ b/include/linux/vmpressure.h @@ -7,6 +7,7 @@ #include #include #include +#include struct vmpressure { unsigned long scanned; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 4bccaa7dda35..feda7c54fa6b 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1352,8 +1352,6 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp) INIT_LIST_HEAD(&cgrp->pidlists); mutex_init(&cgrp->pidlist_mutex); cgrp->dummy_css.cgroup = cgrp; - INIT_LIST_HEAD(&cgrp->event_list); - spin_lock_init(&cgrp->event_list_lock); simple_xattrs_init(&cgrp->xattrs); } diff --git a/mm/memcontrol.c b/mm/memcontrol.c index d00368110b08..2fcacb18404b 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -248,6 +248,22 @@ struct cgroup_event { * Each of these stored in a list by the cgroup. */ struct list_head list; + /* + * register_event() callback will be used to add new userspace + * waiter for changes related to this event. Use eventfd_signal() + * on eventfd to send notification to userspace. + */ + int (*register_event)(struct cgroup_subsys_state *css, + struct cftype *cft, struct eventfd_ctx *eventfd, + const char *args); + /* + * unregister_event() callback will be called when userspace closes + * the eventfd or on cgroup removing. This callback must be set, + * if you want provide notification functionality. + */ + void (*unregister_event)(struct cgroup_subsys_state *css, + struct cftype *cft, + struct eventfd_ctx *eventfd); /* * All fields below needed to unregister event when * userspace closes eventfd. @@ -362,6 +378,10 @@ struct mem_cgroup { atomic_t numainfo_updating; #endif + /* List of events which userspace want to receive */ + struct list_head event_list; + spinlock_t event_list_lock; + struct mem_cgroup_per_node *nodeinfo[0]; /* WARNING: nodeinfo must be the last member here */ }; @@ -5992,7 +6012,7 @@ static void cgroup_event_remove(struct work_struct *work) remove_wait_queue(event->wqh, &event->wait); - event->cft->unregister_event(css, event->cft, event->eventfd); + event->unregister_event(css, event->cft, event->eventfd); /* Notify userspace the event is going away. */ eventfd_signal(event->eventfd, 1); @@ -6012,7 +6032,7 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode, { struct cgroup_event *event = container_of(wait, struct cgroup_event, wait); - struct cgroup *cgrp = event->css->cgroup; + struct mem_cgroup *memcg = mem_cgroup_from_css(event->css); unsigned long flags = (unsigned long)key; if (flags & POLLHUP) { @@ -6025,7 +6045,7 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode, * side will require wqh->lock via remove_wait_queue(), * which we hold. */ - spin_lock(&cgrp->event_list_lock); + spin_lock(&memcg->event_list_lock); if (!list_empty(&event->list)) { list_del_init(&event->list); /* @@ -6034,7 +6054,7 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode, */ schedule_work(&event->remove); } - spin_unlock(&cgrp->event_list_lock); + spin_unlock(&memcg->event_list_lock); } return 0; @@ -6059,12 +6079,13 @@ static void cgroup_event_ptable_queue_proc(struct file *file, static int cgroup_write_event_control(struct cgroup_subsys_state *css, struct cftype *cft, const char *buffer) { - struct cgroup *cgrp = css->cgroup; + struct mem_cgroup *memcg = mem_cgroup_from_css(css); struct cgroup_event *event; struct cgroup_subsys_state *cfile_css; unsigned int efd, cfd; struct fd efile; struct fd cfile; + const char *name; char *endp; int ret; @@ -6118,6 +6139,31 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css, goto out_put_cfile; } + /* + * Determine the event callbacks and set them in @event. This used + * to be done via struct cftype but cgroup core no longer knows + * about these events. The following is crude but the whole thing + * is for compatibility anyway. + */ + name = cfile.file->f_dentry->d_name.name; + + if (!strcmp(name, "memory.usage_in_bytes")) { + event->register_event = mem_cgroup_usage_register_event; + event->unregister_event = mem_cgroup_usage_unregister_event; + } else if (!strcmp(name, "memory.oom_control")) { + event->register_event = mem_cgroup_oom_register_event; + event->unregister_event = mem_cgroup_oom_unregister_event; + } else if (!strcmp(name, "memory.pressure_level")) { + event->register_event = vmpressure_register_event; + event->unregister_event = vmpressure_unregister_event; + } else if (!strcmp(name, "memory.memsw.usage_in_bytes")) { + event->register_event = mem_cgroup_usage_register_event; + event->unregister_event = mem_cgroup_usage_unregister_event; + } else { + ret = -EINVAL; + goto out_put_cfile; + } + /* * Verify @cfile should belong to @css. Also, remaining events are * automatically removed on cgroup destruction but the removal is @@ -6135,21 +6181,15 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css, if (ret) goto out_put_cfile; - if (!event->cft->register_event || !event->cft->unregister_event) { - ret = -EINVAL; - goto out_put_css; - } - - ret = event->cft->register_event(css, event->cft, - event->eventfd, buffer); + ret = event->register_event(css, event->cft, event->eventfd, buffer); if (ret) goto out_put_css; efile.file->f_op->poll(efile.file, &event->pt); - spin_lock(&cgrp->event_list_lock); - list_add(&event->list, &cgrp->event_list); - spin_unlock(&cgrp->event_list_lock); + spin_lock(&memcg->event_list_lock); + list_add(&event->list, &memcg->event_list); + spin_unlock(&memcg->event_list_lock); fdput(cfile); fdput(efile); @@ -6175,8 +6215,6 @@ static struct cftype mem_cgroup_files[] = { .name = "usage_in_bytes", .private = MEMFILE_PRIVATE(_MEM, RES_USAGE), .read = mem_cgroup_read, - .register_event = mem_cgroup_usage_register_event, - .unregister_event = mem_cgroup_usage_unregister_event, }, { .name = "max_usage_in_bytes", @@ -6236,14 +6274,10 @@ static struct cftype mem_cgroup_files[] = { .name = "oom_control", .read_map = mem_cgroup_oom_control_read, .write_u64 = mem_cgroup_oom_control_write, - .register_event = mem_cgroup_oom_register_event, - .unregister_event = mem_cgroup_oom_unregister_event, .private = MEMFILE_PRIVATE(_OOM_TYPE, OOM_CONTROL), }, { .name = "pressure_level", - .register_event = vmpressure_register_event, - .unregister_event = vmpressure_unregister_event, }, #ifdef CONFIG_NUMA { @@ -6291,8 +6325,6 @@ static struct cftype memsw_cgroup_files[] = { .name = "memsw.usage_in_bytes", .private = MEMFILE_PRIVATE(_MEMSWAP, RES_USAGE), .read = mem_cgroup_read, - .register_event = mem_cgroup_usage_register_event, - .unregister_event = mem_cgroup_usage_unregister_event, }, { .name = "memsw.max_usage_in_bytes", @@ -6483,6 +6515,8 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css) mutex_init(&memcg->thresholds_lock); spin_lock_init(&memcg->move_lock); vmpressure_init(&memcg->vmpressure); + INIT_LIST_HEAD(&memcg->event_list); + spin_lock_init(&memcg->event_list_lock); return &memcg->css; @@ -6555,7 +6589,6 @@ static void mem_cgroup_invalidate_reclaim_iterators(struct mem_cgroup *memcg) static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); - struct cgroup *cgrp = css->cgroup; struct cgroup_event *event, *tmp; /* @@ -6563,12 +6596,12 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css) * Notify userspace about cgroup removing only after rmdir of cgroup * directory to avoid race between userspace and kernelspace. */ - spin_lock(&cgrp->event_list_lock); - list_for_each_entry_safe(event, tmp, &cgrp->event_list, list) { + spin_lock(&memcg->event_list_lock); + list_for_each_entry_safe(event, tmp, &memcg->event_list, list) { list_del_init(&event->list); schedule_work(&event->remove); } - spin_unlock(&cgrp->event_list_lock); + spin_unlock(&memcg->event_list_lock); kmem_cgroup_css_offline(memcg); -- cgit v1.2.3-59-g8ed1b From 347c4a8747104a945ecced358944e42879176ca5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 22 Nov 2013 18:20:43 -0500 Subject: memcg: remove cgroup_event->cft The only use of cgroup_event->cft is distinguishing "usage_in_bytes" and "memsw.usgae_in_bytes" for mem_cgroup_usage_[un]register_event(), which can be done by adding an explicit argument to the function and implementing two wrappers so that the two cases can be distinguished from the function alone. Remove cgroup_event->cft and the related code including [un]register_events() methods. Signed-off-by: Tejun Heo Acked-by: Li Zefan Acked-by: Kirill A. Shutemov Acked-by: Michal Hocko --- include/linux/vmpressure.h | 2 -- mm/memcontrol.c | 65 +++++++++++++++++++++++++--------------------- mm/vmpressure.c | 14 +++------- 3 files changed, 38 insertions(+), 43 deletions(-) (limited to 'include/linux') diff --git a/include/linux/vmpressure.h b/include/linux/vmpressure.h index 9dd1914f1a6c..b048365a7ed9 100644 --- a/include/linux/vmpressure.h +++ b/include/linux/vmpressure.h @@ -36,11 +36,9 @@ extern struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg); extern struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr); extern struct vmpressure *css_to_vmpressure(struct cgroup_subsys_state *css); extern int vmpressure_register_event(struct cgroup_subsys_state *css, - struct cftype *cft, struct eventfd_ctx *eventfd, const char *args); extern void vmpressure_unregister_event(struct cgroup_subsys_state *css, - struct cftype *cft, struct eventfd_ctx *eventfd); #else static inline void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 2fcacb18404b..3c93dcfd26da 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -236,10 +236,6 @@ struct cgroup_event { * css which the event belongs to. */ struct cgroup_subsys_state *css; - /* - * Control file which the event associated. - */ - struct cftype *cft; /* * eventfd to signal userspace about the event. */ @@ -254,15 +250,13 @@ struct cgroup_event { * on eventfd to send notification to userspace. */ int (*register_event)(struct cgroup_subsys_state *css, - struct cftype *cft, struct eventfd_ctx *eventfd, - const char *args); + struct eventfd_ctx *eventfd, const char *args); /* * unregister_event() callback will be called when userspace closes * the eventfd or on cgroup removing. This callback must be set, * if you want provide notification functionality. */ void (*unregister_event)(struct cgroup_subsys_state *css, - struct cftype *cft, struct eventfd_ctx *eventfd); /* * All fields below needed to unregister event when @@ -5688,13 +5682,12 @@ static void mem_cgroup_oom_notify(struct mem_cgroup *memcg) mem_cgroup_oom_notify_cb(iter); } -static int mem_cgroup_usage_register_event(struct cgroup_subsys_state *css, - struct cftype *cft, struct eventfd_ctx *eventfd, const char *args) +static int __mem_cgroup_usage_register_event(struct cgroup_subsys_state *css, + struct eventfd_ctx *eventfd, const char *args, enum res_type type) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); struct mem_cgroup_thresholds *thresholds; struct mem_cgroup_threshold_ary *new; - enum res_type type = MEMFILE_TYPE(cft->private); u64 threshold, usage; int i, size, ret; @@ -5771,13 +5764,24 @@ unlock: return ret; } -static void mem_cgroup_usage_unregister_event(struct cgroup_subsys_state *css, - struct cftype *cft, struct eventfd_ctx *eventfd) +static int mem_cgroup_usage_register_event(struct cgroup_subsys_state *css, + struct eventfd_ctx *eventfd, const char *args) +{ + return __mem_cgroup_usage_register_event(css, eventfd, args, _MEM); +} + +static int memsw_cgroup_usage_register_event(struct cgroup_subsys_state *css, + struct eventfd_ctx *eventfd, const char *args) +{ + return __mem_cgroup_usage_register_event(css, eventfd, args, _MEMSWAP); +} + +static void __mem_cgroup_usage_unregister_event(struct cgroup_subsys_state *css, + struct eventfd_ctx *eventfd, enum res_type type) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); struct mem_cgroup_thresholds *thresholds; struct mem_cgroup_threshold_ary *new; - enum res_type type = MEMFILE_TYPE(cft->private); u64 usage; int i, j, size; @@ -5850,14 +5854,24 @@ unlock: mutex_unlock(&memcg->thresholds_lock); } +static void mem_cgroup_usage_unregister_event(struct cgroup_subsys_state *css, + struct eventfd_ctx *eventfd) +{ + return __mem_cgroup_usage_unregister_event(css, eventfd, _MEM); +} + +static void memsw_cgroup_usage_unregister_event(struct cgroup_subsys_state *css, + struct eventfd_ctx *eventfd) +{ + return __mem_cgroup_usage_unregister_event(css, eventfd, _MEMSWAP); +} + static int mem_cgroup_oom_register_event(struct cgroup_subsys_state *css, - struct cftype *cft, struct eventfd_ctx *eventfd, const char *args) + struct eventfd_ctx *eventfd, const char *args) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); struct mem_cgroup_eventfd_list *event; - enum res_type type = MEMFILE_TYPE(cft->private); - BUG_ON(type != _OOM_TYPE); event = kmalloc(sizeof(*event), GFP_KERNEL); if (!event) return -ENOMEM; @@ -5876,13 +5890,10 @@ static int mem_cgroup_oom_register_event(struct cgroup_subsys_state *css, } static void mem_cgroup_oom_unregister_event(struct cgroup_subsys_state *css, - struct cftype *cft, struct eventfd_ctx *eventfd) + struct eventfd_ctx *eventfd) { struct mem_cgroup *memcg = mem_cgroup_from_css(css); struct mem_cgroup_eventfd_list *ev, *tmp; - enum res_type type = MEMFILE_TYPE(cft->private); - - BUG_ON(type != _OOM_TYPE); spin_lock(&memcg_oom_lock); @@ -6012,7 +6023,7 @@ static void cgroup_event_remove(struct work_struct *work) remove_wait_queue(event->wqh, &event->wait); - event->unregister_event(css, event->cft, event->eventfd); + event->unregister_event(css, event->eventfd); /* Notify userspace the event is going away. */ eventfd_signal(event->eventfd, 1); @@ -6133,12 +6144,6 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css, if (ret < 0) goto out_put_cfile; - event->cft = __file_cft(cfile.file); - if (IS_ERR(event->cft)) { - ret = PTR_ERR(event->cft); - goto out_put_cfile; - } - /* * Determine the event callbacks and set them in @event. This used * to be done via struct cftype but cgroup core no longer knows @@ -6157,8 +6162,8 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css, event->register_event = vmpressure_register_event; event->unregister_event = vmpressure_unregister_event; } else if (!strcmp(name, "memory.memsw.usage_in_bytes")) { - event->register_event = mem_cgroup_usage_register_event; - event->unregister_event = mem_cgroup_usage_unregister_event; + event->register_event = memsw_cgroup_usage_register_event; + event->unregister_event = memsw_cgroup_usage_unregister_event; } else { ret = -EINVAL; goto out_put_cfile; @@ -6181,7 +6186,7 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css, if (ret) goto out_put_cfile; - ret = event->register_event(css, event->cft, event->eventfd, buffer); + ret = event->register_event(css, event->eventfd, buffer); if (ret) goto out_put_css; diff --git a/mm/vmpressure.c b/mm/vmpressure.c index e0f62837c3f4..0f25a996d150 100644 --- a/mm/vmpressure.c +++ b/mm/vmpressure.c @@ -279,7 +279,6 @@ void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio) /** * vmpressure_register_event() - Bind vmpressure notifications to an eventfd * @css: css that is interested in vmpressure notifications - * @cft: cgroup control files handle * @eventfd: eventfd context to link notifications with * @args: event arguments (used to set up a pressure level threshold) * @@ -289,13 +288,10 @@ void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio) * threshold (one of vmpressure_str_levels, i.e. "low", "medium", or * "critical"). * - * This function should not be used directly, just pass it to (struct - * cftype).register_event, and then cgroup core will handle everything by - * itself. + * To be used as memcg event method. */ int vmpressure_register_event(struct cgroup_subsys_state *css, - struct cftype *cft, struct eventfd_ctx *eventfd, - const char *args) + struct eventfd_ctx *eventfd, const char *args) { struct vmpressure *vmpr = css_to_vmpressure(css); struct vmpressure_event *ev; @@ -326,19 +322,15 @@ int vmpressure_register_event(struct cgroup_subsys_state *css, /** * vmpressure_unregister_event() - Unbind eventfd from vmpressure * @css: css handle - * @cft: cgroup control files handle * @eventfd: eventfd context that was used to link vmpressure with the @cg * * This function does internal manipulations to detach the @eventfd from * the vmpressure notifications, and then frees internal resources * associated with the @eventfd (but the @eventfd itself is not freed). * - * This function should not be used directly, just pass it to (struct - * cftype).unregister_event, and then cgroup core will handle everything - * by itself. + * To be used as memcg event method. */ void vmpressure_unregister_event(struct cgroup_subsys_state *css, - struct cftype *cft, struct eventfd_ctx *eventfd) { struct vmpressure *vmpr = css_to_vmpressure(css); -- cgit v1.2.3-59-g8ed1b From 59b6f87344ab5eb3057e5844b8cd8a39e668f477 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 22 Nov 2013 18:20:43 -0500 Subject: memcg: make cgroup_event deal with mem_cgroup instead of cgroup_subsys_state cgroup_event is now memcg specific. Replace cgroup_event->css with ->memcg and convert [un]register_event() callbacks to take mem_cgroup pointer instead of cgroup_subsys_state one. This simplifies the code slightly and makes css_to_vmpressure() unnecessary which is removed. Signed-off-by: Tejun Heo Acked-by: Li Zefan Acked-by: Kirill A. Shutemov Acked-by: Michal Hocko --- include/linux/vmpressure.h | 5 ++--- mm/memcontrol.c | 53 +++++++++++++++++++--------------------------- mm/vmpressure.c | 12 +++++------ 3 files changed, 30 insertions(+), 40 deletions(-) (limited to 'include/linux') diff --git a/include/linux/vmpressure.h b/include/linux/vmpressure.h index b048365a7ed9..3e4535876d37 100644 --- a/include/linux/vmpressure.h +++ b/include/linux/vmpressure.h @@ -34,11 +34,10 @@ extern void vmpressure_init(struct vmpressure *vmpr); extern void vmpressure_cleanup(struct vmpressure *vmpr); extern struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg); extern struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr); -extern struct vmpressure *css_to_vmpressure(struct cgroup_subsys_state *css); -extern int vmpressure_register_event(struct cgroup_subsys_state *css, +extern int vmpressure_register_event(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd, const char *args); -extern void vmpressure_unregister_event(struct cgroup_subsys_state *css, +extern void vmpressure_unregister_event(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd); #else static inline void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3c93dcfd26da..42f2843af1a7 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -233,9 +233,9 @@ struct mem_cgroup_eventfd_list { */ struct cgroup_event { /* - * css which the event belongs to. + * memcg which the event belongs to. */ - struct cgroup_subsys_state *css; + struct mem_cgroup *memcg; /* * eventfd to signal userspace about the event. */ @@ -249,14 +249,14 @@ struct cgroup_event { * waiter for changes related to this event. Use eventfd_signal() * on eventfd to send notification to userspace. */ - int (*register_event)(struct cgroup_subsys_state *css, + int (*register_event)(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd, const char *args); /* * unregister_event() callback will be called when userspace closes * the eventfd or on cgroup removing. This callback must be set, * if you want provide notification functionality. */ - void (*unregister_event)(struct cgroup_subsys_state *css, + void (*unregister_event)(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd); /* * All fields below needed to unregister event when @@ -535,11 +535,6 @@ struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr) return &container_of(vmpr, struct mem_cgroup, vmpressure)->css; } -struct vmpressure *css_to_vmpressure(struct cgroup_subsys_state *css) -{ - return &mem_cgroup_from_css(css)->vmpressure; -} - static inline bool mem_cgroup_is_root(struct mem_cgroup *memcg) { return (memcg == root_mem_cgroup); @@ -5682,10 +5677,9 @@ static void mem_cgroup_oom_notify(struct mem_cgroup *memcg) mem_cgroup_oom_notify_cb(iter); } -static int __mem_cgroup_usage_register_event(struct cgroup_subsys_state *css, +static int __mem_cgroup_usage_register_event(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd, const char *args, enum res_type type) { - struct mem_cgroup *memcg = mem_cgroup_from_css(css); struct mem_cgroup_thresholds *thresholds; struct mem_cgroup_threshold_ary *new; u64 threshold, usage; @@ -5764,22 +5758,21 @@ unlock: return ret; } -static int mem_cgroup_usage_register_event(struct cgroup_subsys_state *css, +static int mem_cgroup_usage_register_event(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd, const char *args) { - return __mem_cgroup_usage_register_event(css, eventfd, args, _MEM); + return __mem_cgroup_usage_register_event(memcg, eventfd, args, _MEM); } -static int memsw_cgroup_usage_register_event(struct cgroup_subsys_state *css, +static int memsw_cgroup_usage_register_event(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd, const char *args) { - return __mem_cgroup_usage_register_event(css, eventfd, args, _MEMSWAP); + return __mem_cgroup_usage_register_event(memcg, eventfd, args, _MEMSWAP); } -static void __mem_cgroup_usage_unregister_event(struct cgroup_subsys_state *css, +static void __mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd, enum res_type type) { - struct mem_cgroup *memcg = mem_cgroup_from_css(css); struct mem_cgroup_thresholds *thresholds; struct mem_cgroup_threshold_ary *new; u64 usage; @@ -5854,22 +5847,21 @@ unlock: mutex_unlock(&memcg->thresholds_lock); } -static void mem_cgroup_usage_unregister_event(struct cgroup_subsys_state *css, +static void mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd) { - return __mem_cgroup_usage_unregister_event(css, eventfd, _MEM); + return __mem_cgroup_usage_unregister_event(memcg, eventfd, _MEM); } -static void memsw_cgroup_usage_unregister_event(struct cgroup_subsys_state *css, +static void memsw_cgroup_usage_unregister_event(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd) { - return __mem_cgroup_usage_unregister_event(css, eventfd, _MEMSWAP); + return __mem_cgroup_usage_unregister_event(memcg, eventfd, _MEMSWAP); } -static int mem_cgroup_oom_register_event(struct cgroup_subsys_state *css, +static int mem_cgroup_oom_register_event(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd, const char *args) { - struct mem_cgroup *memcg = mem_cgroup_from_css(css); struct mem_cgroup_eventfd_list *event; event = kmalloc(sizeof(*event), GFP_KERNEL); @@ -5889,10 +5881,9 @@ static int mem_cgroup_oom_register_event(struct cgroup_subsys_state *css, return 0; } -static void mem_cgroup_oom_unregister_event(struct cgroup_subsys_state *css, +static void mem_cgroup_oom_unregister_event(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd) { - struct mem_cgroup *memcg = mem_cgroup_from_css(css); struct mem_cgroup_eventfd_list *ev, *tmp; spin_lock(&memcg_oom_lock); @@ -6019,18 +6010,18 @@ static void cgroup_event_remove(struct work_struct *work) { struct cgroup_event *event = container_of(work, struct cgroup_event, remove); - struct cgroup_subsys_state *css = event->css; + struct mem_cgroup *memcg = event->memcg; remove_wait_queue(event->wqh, &event->wait); - event->unregister_event(css, event->eventfd); + event->unregister_event(memcg, event->eventfd); /* Notify userspace the event is going away. */ eventfd_signal(event->eventfd, 1); eventfd_ctx_put(event->eventfd); kfree(event); - css_put(css); + css_put(&memcg->css); } /* @@ -6043,7 +6034,7 @@ static int cgroup_event_wake(wait_queue_t *wait, unsigned mode, { struct cgroup_event *event = container_of(wait, struct cgroup_event, wait); - struct mem_cgroup *memcg = mem_cgroup_from_css(event->css); + struct mem_cgroup *memcg = event->memcg; unsigned long flags = (unsigned long)key; if (flags & POLLHUP) { @@ -6114,7 +6105,7 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css, if (!event) return -ENOMEM; - event->css = css; + event->memcg = memcg; INIT_LIST_HEAD(&event->list); init_poll_funcptr(&event->pt, cgroup_event_ptable_queue_proc); init_waitqueue_func_entry(&event->wait, cgroup_event_wake); @@ -6186,7 +6177,7 @@ static int cgroup_write_event_control(struct cgroup_subsys_state *css, if (ret) goto out_put_cfile; - ret = event->register_event(css, event->eventfd, buffer); + ret = event->register_event(memcg, event->eventfd, buffer); if (ret) goto out_put_css; diff --git a/mm/vmpressure.c b/mm/vmpressure.c index 0f25a996d150..196970a4541f 100644 --- a/mm/vmpressure.c +++ b/mm/vmpressure.c @@ -278,7 +278,7 @@ void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio) /** * vmpressure_register_event() - Bind vmpressure notifications to an eventfd - * @css: css that is interested in vmpressure notifications + * @memcg: memcg that is interested in vmpressure notifications * @eventfd: eventfd context to link notifications with * @args: event arguments (used to set up a pressure level threshold) * @@ -290,10 +290,10 @@ void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio) * * To be used as memcg event method. */ -int vmpressure_register_event(struct cgroup_subsys_state *css, +int vmpressure_register_event(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd, const char *args) { - struct vmpressure *vmpr = css_to_vmpressure(css); + struct vmpressure *vmpr = memcg_to_vmpressure(memcg); struct vmpressure_event *ev; int level; @@ -321,7 +321,7 @@ int vmpressure_register_event(struct cgroup_subsys_state *css, /** * vmpressure_unregister_event() - Unbind eventfd from vmpressure - * @css: css handle + * @memcg: memcg handle * @eventfd: eventfd context that was used to link vmpressure with the @cg * * This function does internal manipulations to detach the @eventfd from @@ -330,10 +330,10 @@ int vmpressure_register_event(struct cgroup_subsys_state *css, * * To be used as memcg event method. */ -void vmpressure_unregister_event(struct cgroup_subsys_state *css, +void vmpressure_unregister_event(struct mem_cgroup *memcg, struct eventfd_ctx *eventfd) { - struct vmpressure *vmpr = css_to_vmpressure(css); + struct vmpressure *vmpr = memcg_to_vmpressure(memcg); struct vmpressure_event *ev; mutex_lock(&vmpr->events_lock); -- cgit v1.2.3-59-g8ed1b From b36824c75c7855585d6476eef2b234f6e0e68872 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 22 Nov 2013 18:20:44 -0500 Subject: cgroup: unexport cgroup_css() and remove __file_cft() Now that cgroup_event is made memcg specific, the temporarily exported functions are no longer necessary. Unexport cgroup_css() and remove __file_cft() which doesn't have any user left. Signed-off-by: Tejun Heo Acked-by: Li Zefan Acked-by: Kirill A. Shutemov --- include/linux/cgroup.h | 5 ----- kernel/cgroup.c | 14 ++------------ 2 files changed, 2 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 612adc5b87c5..8d9fa8967c9e 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -883,11 +883,6 @@ unsigned short css_id(struct cgroup_subsys_state *css); struct cgroup_subsys_state *css_from_dir(struct dentry *dentry, struct cgroup_subsys *ss); -/* XXX: temporary */ -struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, - struct cgroup_subsys *ss); -struct cftype *__file_cft(struct file *file); - #else /* !CONFIG_CGROUPS */ static inline int cgroup_init_early(void) { return 0; } diff --git a/kernel/cgroup.c b/kernel/cgroup.c index feda7c54fa6b..c0248e16461d 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -202,8 +202,8 @@ static int cgroup_addrm_files(struct cgroup *cgrp, struct cftype cfts[], * keep accessing it outside the said locks. This function may return * %NULL if @cgrp doesn't have @subsys_id enabled. */ -struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, - struct cgroup_subsys *ss) +static struct cgroup_subsys_state *cgroup_css(struct cgroup *cgrp, + struct cgroup_subsys *ss) { if (ss) return rcu_dereference_check(cgrp->subsys[ss->subsys_id], @@ -2625,16 +2625,6 @@ static const struct inode_operations cgroup_dir_inode_operations = { .removexattr = cgroup_removexattr, }; -/* - * Check if a file is a control file - */ -struct cftype *__file_cft(struct file *file) -{ - if (file_inode(file)->i_fop != &cgroup_file_operations) - return ERR_PTR(-EINVAL); - return __d_cft(file->f_dentry); -} - static int cgroup_create_file(struct dentry *dentry, umode_t mode, struct super_block *sb) { -- cgit v1.2.3-59-g8ed1b From 4f024f3797c43cb4b73cd2c50cec728842d0e49e Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Fri, 11 Oct 2013 15:44:27 -0700 Subject: block: Abstract out bvec iterator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Immutable biovecs are going to require an explicit iterator. To implement immutable bvecs, a later patch is going to add a bi_bvec_done member to this struct; for now, this patch effectively just renames things. Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: Geert Uytterhoeven Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: "Ed L. Cashin" Cc: Nick Piggin Cc: Lars Ellenberg Cc: Jiri Kosina Cc: Matthew Wilcox Cc: Geoff Levand Cc: Yehuda Sadeh Cc: Sage Weil Cc: Alex Elder Cc: ceph-devel@vger.kernel.org Cc: Joshua Morris Cc: Philip Kelleher Cc: Rusty Russell Cc: "Michael S. Tsirkin" Cc: Konrad Rzeszutek Wilk Cc: Jeremy Fitzhardinge Cc: Neil Brown Cc: Alasdair Kergon Cc: Mike Snitzer Cc: dm-devel@redhat.com Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Cc: Boaz Harrosh Cc: Benny Halevy Cc: "James E.J. Bottomley" Cc: Greg Kroah-Hartman Cc: "Nicholas A. Bellinger" Cc: Alexander Viro Cc: Chris Mason Cc: "Theodore Ts'o" Cc: Andreas Dilger Cc: Jaegeuk Kim Cc: Steven Whitehouse Cc: Dave Kleikamp Cc: Joern Engel Cc: Prasad Joshi Cc: Trond Myklebust Cc: KONISHI Ryusuke Cc: Mark Fasheh Cc: Joel Becker Cc: Ben Myers Cc: xfs@oss.sgi.com Cc: Steven Rostedt Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Len Brown Cc: Pavel Machek Cc: "Rafael J. Wysocki" Cc: Herton Ronaldo Krzesinski Cc: Ben Hutchings Cc: Andrew Morton Cc: Guo Chao Cc: Tejun Heo Cc: Asai Thambi S P Cc: Selvan Mani Cc: Sam Bradshaw Cc: Wei Yongjun Cc: "Roger Pau Monné" Cc: Jan Beulich Cc: Stefano Stabellini Cc: Ian Campbell Cc: Sebastian Ott Cc: Christian Borntraeger Cc: Minchan Kim Cc: Jiang Liu Cc: Nitin Gupta Cc: Jerome Marchand Cc: Joe Perches Cc: Peng Tao Cc: Andy Adamson Cc: fanchaoting Cc: Jie Liu Cc: Sunil Mushran Cc: "Martin K. Petersen" Cc: Namjae Jeon Cc: Pankaj Kumar Cc: Dan Magenheimer Cc: Mel Gorman 6 --- Documentation/block/biodoc.txt | 7 +-- arch/m68k/emu/nfblock.c | 2 +- arch/powerpc/sysdev/axonram.c | 3 +- block/blk-core.c | 36 ++++++------ block/blk-flush.c | 2 +- block/blk-lib.c | 12 ++-- block/blk-map.c | 6 +- block/blk-merge.c | 4 +- block/blk-mq.c | 2 +- block/blk-throttle.c | 14 ++--- block/elevator.c | 2 +- drivers/block/aoe/aoecmd.c | 6 +- drivers/block/brd.c | 4 +- drivers/block/drbd/drbd_actlog.c | 2 +- drivers/block/drbd/drbd_bitmap.c | 2 +- drivers/block/drbd/drbd_receiver.c | 6 +- drivers/block/drbd/drbd_req.c | 6 +- drivers/block/drbd/drbd_req.h | 2 +- drivers/block/floppy.c | 4 +- drivers/block/loop.c | 4 +- drivers/block/mtip32xx/mtip32xx.c | 7 ++- drivers/block/nvme-core.c | 25 ++++---- drivers/block/pktcdvd.c | 54 +++++++++-------- drivers/block/ps3disk.c | 2 +- drivers/block/ps3vram.c | 2 +- drivers/block/rbd.c | 21 +++---- drivers/block/rsxx/dev.c | 6 +- drivers/block/rsxx/dma.c | 4 +- drivers/block/umem.c | 9 +-- drivers/block/xen-blkback/blkback.c | 2 +- drivers/block/xen-blkfront.c | 2 +- drivers/md/bcache/btree.c | 4 +- drivers/md/bcache/debug.c | 2 +- drivers/md/bcache/io.c | 26 ++++----- drivers/md/bcache/journal.c | 12 ++-- drivers/md/bcache/movinggc.c | 4 +- drivers/md/bcache/request.c | 58 +++++++++--------- drivers/md/bcache/super.c | 16 ++--- drivers/md/bcache/util.c | 4 +- drivers/md/bcache/writeback.c | 6 +- drivers/md/bcache/writeback.h | 2 +- drivers/md/dm-bio-record.h | 12 ++-- drivers/md/dm-bufio.c | 2 +- drivers/md/dm-cache-policy-mq.c | 4 +- drivers/md/dm-cache-target.c | 22 +++---- drivers/md/dm-crypt.c | 19 +++--- drivers/md/dm-delay.c | 7 ++- drivers/md/dm-flakey.c | 7 ++- drivers/md/dm-io.c | 6 +- drivers/md/dm-linear.c | 3 +- drivers/md/dm-raid1.c | 16 ++--- drivers/md/dm-region-hash.c | 3 +- drivers/md/dm-snap.c | 18 +++--- drivers/md/dm-stripe.c | 13 +++-- drivers/md/dm-switch.c | 4 +- drivers/md/dm-thin.c | 22 +++---- drivers/md/dm-verity.c | 8 +-- drivers/md/dm.c | 25 ++++---- drivers/md/faulty.c | 19 +++--- drivers/md/linear.c | 12 ++-- drivers/md/md.c | 10 ++-- drivers/md/multipath.c | 13 +++-- drivers/md/raid0.c | 16 ++--- drivers/md/raid1.c | 75 ++++++++++++------------ drivers/md/raid10.c | 91 ++++++++++++++++------------- drivers/md/raid5.c | 72 ++++++++++++----------- drivers/s390/block/dcssblk.c | 5 +- drivers/s390/block/xpram.c | 9 +-- drivers/scsi/osd/osd_initiator.c | 2 +- drivers/staging/lustre/lustre/llite/lloop.c | 12 ++-- drivers/staging/zram/zram_drv.c | 14 +++-- drivers/target/target_core_iblock.c | 2 +- fs/bio-integrity.c | 8 +-- fs/bio.c | 56 +++++++++--------- fs/btrfs/check-integrity.c | 8 +-- fs/btrfs/compression.c | 17 +++--- fs/btrfs/extent_io.c | 14 ++--- fs/btrfs/file-item.c | 19 +++--- fs/btrfs/inode.c | 22 +++---- fs/btrfs/raid56.c | 22 +++---- fs/btrfs/scrub.c | 12 ++-- fs/btrfs/volumes.c | 12 ++-- fs/buffer.c | 12 ++-- fs/direct-io.c | 4 +- fs/ext4/page-io.c | 4 +- fs/f2fs/data.c | 2 +- fs/f2fs/segment.c | 2 +- fs/gfs2/lops.c | 2 +- fs/gfs2/ops_fstype.c | 2 +- fs/hfsplus/wrapper.c | 2 +- fs/jfs/jfs_logmgr.c | 12 ++-- fs/jfs/jfs_metapage.c | 9 +-- fs/logfs/dev_bdev.c | 20 +++---- fs/mpage.c | 2 +- fs/nfs/blocklayout/blocklayout.c | 9 +-- fs/nilfs2/segbuf.c | 3 +- fs/ocfs2/cluster/heartbeat.c | 2 +- fs/xfs/xfs_aops.c | 2 +- fs/xfs/xfs_buf.c | 4 +- include/linux/bio.h | 16 ++--- include/linux/blk_types.h | 19 +++--- include/trace/events/bcache.h | 26 ++++----- include/trace/events/block.h | 26 ++++----- include/trace/events/f2fs.h | 4 +- kernel/power/block_io.c | 2 +- kernel/trace/blktrace.c | 15 ++--- mm/page_io.c | 10 ++-- 107 files changed, 700 insertions(+), 638 deletions(-) (limited to 'include/linux') diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt index 8df5e8e6dceb..2101e718670d 100644 --- a/Documentation/block/biodoc.txt +++ b/Documentation/block/biodoc.txt @@ -447,14 +447,13 @@ struct bio_vec { * main unit of I/O for the block layer and lower layers (ie drivers) */ struct bio { - sector_t bi_sector; struct bio *bi_next; /* request queue link */ struct block_device *bi_bdev; /* target device */ unsigned long bi_flags; /* status, command, etc */ unsigned long bi_rw; /* low bits: r/w, high: priority */ unsigned int bi_vcnt; /* how may bio_vec's */ - unsigned int bi_idx; /* current index into bio_vec array */ + struct bvec_iter bi_iter; /* current index into bio_vec array */ unsigned int bi_size; /* total size in bytes */ unsigned short bi_phys_segments; /* segments after physaddr coalesce*/ @@ -480,7 +479,7 @@ With this multipage bio design: - Code that traverses the req list can find all the segments of a bio by using rq_for_each_segment. This handles the fact that a request has multiple bios, each of which can have multiple segments. -- Drivers which can't process a large bio in one shot can use the bi_idx +- Drivers which can't process a large bio in one shot can use the bi_iter field to keep track of the next bio_vec entry to process. (e.g a 1MB bio_vec needs to be handled in max 128kB chunks for IDE) [TBD: Should preferably also have a bi_voffset and bi_vlen to avoid modifying @@ -589,7 +588,7 @@ driver should not modify these values. The block layer sets up the nr_sectors and current_nr_sectors fields (based on the corresponding hard_xxx values and the number of bytes transferred) and updates it on every transfer that invokes end_that_request_first. It does the same for the -buffer, bio, bio->bi_idx fields too. +buffer, bio, bio->bi_iter fields too. The buffer field is just a virtual address mapping of the current segment of the i/o buffer in cases where the buffer resides in low-memory. For high diff --git a/arch/m68k/emu/nfblock.c b/arch/m68k/emu/nfblock.c index 0721858fbd1e..0a9d0b3c794b 100644 --- a/arch/m68k/emu/nfblock.c +++ b/arch/m68k/emu/nfblock.c @@ -64,7 +64,7 @@ static void nfhd_make_request(struct request_queue *queue, struct bio *bio) struct nfhd_device *dev = queue->queuedata; struct bio_vec *bvec; int i, dir, len, shift; - sector_t sec = bio->bi_sector; + sector_t sec = bio->bi_iter.bi_sector; dir = bio_data_dir(bio); shift = dev->bshift; diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 1c16141c031c..f33bcbaa6a07 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -113,7 +113,8 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) unsigned int transfered; unsigned short idx; - phys_mem = bank->io_addr + (bio->bi_sector << AXON_RAM_SECTOR_SHIFT); + phys_mem = bank->io_addr + (bio->bi_iter.bi_sector << + AXON_RAM_SECTOR_SHIFT); phys_end = bank->io_addr + bank->size; transfered = 0; bio_for_each_segment(vec, bio, idx) { diff --git a/block/blk-core.c b/block/blk-core.c index 8bdd0121212a..5c2ab2c74066 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -130,7 +130,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio, bio_advance(bio, nbytes); /* don't actually finish bio if it's part of flush sequence */ - if (bio->bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ)) + if (bio->bi_iter.bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ)) bio_endio(bio, error); } @@ -1326,7 +1326,7 @@ void blk_add_request_payload(struct request *rq, struct page *page, bio->bi_io_vec->bv_offset = 0; bio->bi_io_vec->bv_len = len; - bio->bi_size = len; + bio->bi_iter.bi_size = len; bio->bi_vcnt = 1; bio->bi_phys_segments = 1; @@ -1351,7 +1351,7 @@ bool bio_attempt_back_merge(struct request_queue *q, struct request *req, req->biotail->bi_next = bio; req->biotail = bio; - req->__data_len += bio->bi_size; + req->__data_len += bio->bi_iter.bi_size; req->ioprio = ioprio_best(req->ioprio, bio_prio(bio)); blk_account_io_start(req, false); @@ -1380,8 +1380,8 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req, * not touch req->buffer either... */ req->buffer = bio_data(bio); - req->__sector = bio->bi_sector; - req->__data_len += bio->bi_size; + req->__sector = bio->bi_iter.bi_sector; + req->__data_len += bio->bi_iter.bi_size; req->ioprio = ioprio_best(req->ioprio, bio_prio(bio)); blk_account_io_start(req, false); @@ -1459,7 +1459,7 @@ void init_request_from_bio(struct request *req, struct bio *bio) req->cmd_flags |= REQ_FAILFAST_MASK; req->errors = 0; - req->__sector = bio->bi_sector; + req->__sector = bio->bi_iter.bi_sector; req->ioprio = bio_prio(bio); blk_rq_bio_prep(req->q, req, bio); } @@ -1583,12 +1583,12 @@ static inline void blk_partition_remap(struct bio *bio) if (bio_sectors(bio) && bdev != bdev->bd_contains) { struct hd_struct *p = bdev->bd_part; - bio->bi_sector += p->start_sect; + bio->bi_iter.bi_sector += p->start_sect; bio->bi_bdev = bdev->bd_contains; trace_block_bio_remap(bdev_get_queue(bio->bi_bdev), bio, bdev->bd_dev, - bio->bi_sector - p->start_sect); + bio->bi_iter.bi_sector - p->start_sect); } } @@ -1654,7 +1654,7 @@ static inline int bio_check_eod(struct bio *bio, unsigned int nr_sectors) /* Test device or partition size, when known. */ maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9; if (maxsector) { - sector_t sector = bio->bi_sector; + sector_t sector = bio->bi_iter.bi_sector; if (maxsector < nr_sectors || maxsector - nr_sectors < sector) { /* @@ -1690,7 +1690,7 @@ generic_make_request_checks(struct bio *bio) "generic_make_request: Trying to access " "nonexistent block-device %s (%Lu)\n", bdevname(bio->bi_bdev, b), - (long long) bio->bi_sector); + (long long) bio->bi_iter.bi_sector); goto end_io; } @@ -1704,9 +1704,9 @@ generic_make_request_checks(struct bio *bio) } part = bio->bi_bdev->bd_part; - if (should_fail_request(part, bio->bi_size) || + if (should_fail_request(part, bio->bi_iter.bi_size) || should_fail_request(&part_to_disk(part)->part0, - bio->bi_size)) + bio->bi_iter.bi_size)) goto end_io; /* @@ -1865,7 +1865,7 @@ void submit_bio(int rw, struct bio *bio) if (rw & WRITE) { count_vm_events(PGPGOUT, count); } else { - task_io_account_read(bio->bi_size); + task_io_account_read(bio->bi_iter.bi_size); count_vm_events(PGPGIN, count); } @@ -1874,7 +1874,7 @@ void submit_bio(int rw, struct bio *bio) printk(KERN_DEBUG "%s(%d): %s block %Lu on %s (%u sectors)\n", current->comm, task_pid_nr(current), (rw & WRITE) ? "WRITE" : "READ", - (unsigned long long)bio->bi_sector, + (unsigned long long)bio->bi_iter.bi_sector, bdevname(bio->bi_bdev, b), count); } @@ -2007,7 +2007,7 @@ unsigned int blk_rq_err_bytes(const struct request *rq) for (bio = rq->bio; bio; bio = bio->bi_next) { if ((bio->bi_rw & ff) != ff) break; - bytes += bio->bi_size; + bytes += bio->bi_iter.bi_size; } /* this could lead to infinite loop */ @@ -2378,9 +2378,9 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) total_bytes = 0; while (req->bio) { struct bio *bio = req->bio; - unsigned bio_bytes = min(bio->bi_size, nr_bytes); + unsigned bio_bytes = min(bio->bi_iter.bi_size, nr_bytes); - if (bio_bytes == bio->bi_size) + if (bio_bytes == bio->bi_iter.bi_size) req->bio = bio->bi_next; req_bio_endio(req, bio, bio_bytes, error); @@ -2728,7 +2728,7 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, rq->nr_phys_segments = bio_phys_segments(q, bio); rq->buffer = bio_data(bio); } - rq->__data_len = bio->bi_size; + rq->__data_len = bio->bi_iter.bi_size; rq->bio = rq->biotail = bio; if (bio->bi_bdev) diff --git a/block/blk-flush.c b/block/blk-flush.c index fb6f3c0ffa49..9288aaf35c21 100644 --- a/block/blk-flush.c +++ b/block/blk-flush.c @@ -548,7 +548,7 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask, * copied from blk_rq_pos(rq). */ if (error_sector) - *error_sector = bio->bi_sector; + *error_sector = bio->bi_iter.bi_sector; bio_put(bio); return ret; diff --git a/block/blk-lib.c b/block/blk-lib.c index 9b5b561cb928..2da76c999ef3 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -108,12 +108,12 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector, req_sects = end_sect - sector; } - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_end_io = bio_batch_end_io; bio->bi_bdev = bdev; bio->bi_private = &bb; - bio->bi_size = req_sects << 9; + bio->bi_iter.bi_size = req_sects << 9; nr_sects -= req_sects; sector = end_sect; @@ -174,7 +174,7 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, break; } - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_end_io = bio_batch_end_io; bio->bi_bdev = bdev; bio->bi_private = &bb; @@ -184,11 +184,11 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, bio->bi_io_vec->bv_len = bdev_logical_block_size(bdev); if (nr_sects > max_write_same_sectors) { - bio->bi_size = max_write_same_sectors << 9; + bio->bi_iter.bi_size = max_write_same_sectors << 9; nr_sects -= max_write_same_sectors; sector += max_write_same_sectors; } else { - bio->bi_size = nr_sects << 9; + bio->bi_iter.bi_size = nr_sects << 9; nr_sects = 0; } @@ -240,7 +240,7 @@ int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, break; } - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_bdev = bdev; bio->bi_end_io = bio_batch_end_io; bio->bi_private = &bb; diff --git a/block/blk-map.c b/block/blk-map.c index 623e1cd4cffe..ae4ae1047fd9 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -20,7 +20,7 @@ int blk_rq_append_bio(struct request_queue *q, struct request *rq, rq->biotail->bi_next = bio; rq->biotail = bio; - rq->__data_len += bio->bi_size; + rq->__data_len += bio->bi_iter.bi_size; } return 0; } @@ -76,7 +76,7 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq, ret = blk_rq_append_bio(q, rq, bio); if (!ret) - return bio->bi_size; + return bio->bi_iter.bi_size; /* if it was boucned we must call the end io function */ bio_endio(bio, 0); @@ -220,7 +220,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, if (IS_ERR(bio)) return PTR_ERR(bio); - if (bio->bi_size != len) { + if (bio->bi_iter.bi_size != len) { /* * Grab an extra reference to this bio, as bio_unmap_user() * expects to be able to drop it twice as it happens on the diff --git a/block/blk-merge.c b/block/blk-merge.c index 1ffc58977835..03bc083c28cf 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -543,9 +543,9 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio) int blk_try_merge(struct request *rq, struct bio *bio) { - if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_sector) + if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_iter.bi_sector) return ELEVATOR_BACK_MERGE; - else if (blk_rq_pos(rq) - bio_sectors(bio) == bio->bi_sector) + else if (blk_rq_pos(rq) - bio_sectors(bio) == bio->bi_iter.bi_sector) return ELEVATOR_FRONT_MERGE; return ELEVATOR_NO_MERGE; } diff --git a/block/blk-mq.c b/block/blk-mq.c index cdc629cf075b..e4fbcc3fd2db 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -301,7 +301,7 @@ void blk_mq_complete_request(struct request *rq, int error) struct bio *next = bio->bi_next; bio->bi_next = NULL; - bytes += bio->bi_size; + bytes += bio->bi_iter.bi_size; blk_mq_bio_endio(rq, bio, error); bio = next; } diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 06534049afba..20f820037775 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -877,14 +877,14 @@ static bool tg_with_in_bps_limit(struct throtl_grp *tg, struct bio *bio, do_div(tmp, HZ); bytes_allowed = tmp; - if (tg->bytes_disp[rw] + bio->bi_size <= bytes_allowed) { + if (tg->bytes_disp[rw] + bio->bi_iter.bi_size <= bytes_allowed) { if (wait) *wait = 0; return 1; } /* Calc approx time to dispatch */ - extra_bytes = tg->bytes_disp[rw] + bio->bi_size - bytes_allowed; + extra_bytes = tg->bytes_disp[rw] + bio->bi_iter.bi_size - bytes_allowed; jiffy_wait = div64_u64(extra_bytes * HZ, tg->bps[rw]); if (!jiffy_wait) @@ -987,7 +987,7 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio) bool rw = bio_data_dir(bio); /* Charge the bio to the group */ - tg->bytes_disp[rw] += bio->bi_size; + tg->bytes_disp[rw] += bio->bi_iter.bi_size; tg->io_disp[rw]++; /* @@ -1003,8 +1003,8 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio) */ if (!(bio->bi_rw & REQ_THROTTLED)) { bio->bi_rw |= REQ_THROTTLED; - throtl_update_dispatch_stats(tg_to_blkg(tg), bio->bi_size, - bio->bi_rw); + throtl_update_dispatch_stats(tg_to_blkg(tg), + bio->bi_iter.bi_size, bio->bi_rw); } } @@ -1508,7 +1508,7 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio) if (tg) { if (!tg->has_rules[rw]) { throtl_update_dispatch_stats(tg_to_blkg(tg), - bio->bi_size, bio->bi_rw); + bio->bi_iter.bi_size, bio->bi_rw); goto out_unlock_rcu; } } @@ -1564,7 +1564,7 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio) /* out-of-limit, queue to @tg */ throtl_log(sq, "[%c] bio. bdisp=%llu sz=%u bps=%llu iodisp=%u iops=%u queued=%d/%d", rw == READ ? 'R' : 'W', - tg->bytes_disp[rw], bio->bi_size, tg->bps[rw], + tg->bytes_disp[rw], bio->bi_iter.bi_size, tg->bps[rw], tg->io_disp[rw], tg->iops[rw], sq->nr_queued[READ], sq->nr_queued[WRITE]); diff --git a/block/elevator.c b/block/elevator.c index b7ff2861b6bd..42c45a7d6714 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -440,7 +440,7 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio) /* * See if our hash lookup can find a potential backmerge. */ - __rq = elv_rqhash_find(q, bio->bi_sector); + __rq = elv_rqhash_find(q, bio->bi_iter.bi_sector); if (__rq && elv_rq_merge_ok(__rq, bio)) { *req = __rq; return ELEVATOR_BACK_MERGE; diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index d2515435e23f..877ba119b3f8 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -929,8 +929,8 @@ bufinit(struct buf *buf, struct request *rq, struct bio *bio) memset(buf, 0, sizeof(*buf)); buf->rq = rq; buf->bio = bio; - buf->resid = bio->bi_size; - buf->sector = bio->bi_sector; + buf->resid = bio->bi_iter.bi_size; + buf->sector = bio->bi_iter.bi_sector; bio_pageinc(bio); buf->bv = bio_iovec(bio); buf->bv_resid = buf->bv->bv_len; @@ -1152,7 +1152,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail) do { bio = rq->bio; bok = !fastfail && test_bit(BIO_UPTODATE, &bio->bi_flags); - } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_size)); + } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_iter.bi_size)); /* cf. http://lkml.org/lkml/2006/10/31/28 */ if (!fastfail) diff --git a/drivers/block/brd.c b/drivers/block/brd.c index d91f1a56e861..66f5aaae15a2 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -333,13 +333,13 @@ static void brd_make_request(struct request_queue *q, struct bio *bio) int i; int err = -EIO; - sector = bio->bi_sector; + sector = bio->bi_iter.bi_sector; if (bio_end_sector(bio) > get_capacity(bdev->bd_disk)) goto out; if (unlikely(bio->bi_rw & REQ_DISCARD)) { err = 0; - discard_from_brd(brd, sector, bio->bi_size); + discard_from_brd(brd, sector, bio->bi_iter.bi_size); goto out; } diff --git a/drivers/block/drbd/drbd_actlog.c b/drivers/block/drbd/drbd_actlog.c index 28c73ca320a8..a9b13f2cc420 100644 --- a/drivers/block/drbd/drbd_actlog.c +++ b/drivers/block/drbd/drbd_actlog.c @@ -159,7 +159,7 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev, bio = bio_alloc_drbd(GFP_NOIO); bio->bi_bdev = bdev->md_bdev; - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; err = -EIO; if (bio_add_page(bio, page, size, 0) != size) goto out; diff --git a/drivers/block/drbd/drbd_bitmap.c b/drivers/block/drbd/drbd_bitmap.c index b12c11ec4bd2..597f111df67b 100644 --- a/drivers/block/drbd/drbd_bitmap.c +++ b/drivers/block/drbd/drbd_bitmap.c @@ -1028,7 +1028,7 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must } else page = b->bm_pages[page_nr]; bio->bi_bdev = mdev->ldev->md_bdev; - bio->bi_sector = on_disk_sector; + bio->bi_iter.bi_sector = on_disk_sector; /* bio_add_page of a single page to an empty bio will always succeed, * according to api. Do we want to assert that? */ bio_add_page(bio, page, len, 0); diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 6fa6673b36b3..5326c22cdb9d 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1333,7 +1333,7 @@ next_bio: goto fail; } /* > peer_req->i.sector, unless this is the first bio */ - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_bdev = mdev->ldev->backing_bdev; bio->bi_rw = rw; bio->bi_private = peer_req; @@ -1353,7 +1353,7 @@ next_bio: dev_err(DEV, "bio_add_page failed for len=%u, " "bi_vcnt=0 (bi_sector=%llu)\n", - len, (unsigned long long)bio->bi_sector); + len, (uint64_t)bio->bi_iter.bi_sector); err = -ENOSPC; goto fail; } @@ -1615,7 +1615,7 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, mdev->recv_cnt += data_size>>9; bio = req->master_bio; - D_ASSERT(sector == bio->bi_sector); + D_ASSERT(sector == bio->bi_iter.bi_sector); bio_for_each_segment(bvec, bio, i) { void *mapped = kmap(bvec->bv_page) + bvec->bv_offset; diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index fec7bef44994..104a040f24de 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c @@ -77,8 +77,8 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev, req->epoch = 0; drbd_clear_interval(&req->i); - req->i.sector = bio_src->bi_sector; - req->i.size = bio_src->bi_size; + req->i.sector = bio_src->bi_iter.bi_sector; + req->i.size = bio_src->bi_iter.bi_size; req->i.local = true; req->i.waiting = false; @@ -1280,7 +1280,7 @@ void drbd_make_request(struct request_queue *q, struct bio *bio) /* * what we "blindly" assume: */ - D_ASSERT(IS_ALIGNED(bio->bi_size, 512)); + D_ASSERT(IS_ALIGNED(bio->bi_iter.bi_size, 512)); inc_ap_bio(mdev); __drbd_make_request(mdev, bio, start_time); diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 978cb1addc98..28e15d91197a 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h @@ -269,7 +269,7 @@ static inline void drbd_req_make_private_bio(struct drbd_request *req, struct bi /* Short lived temporary struct on the stack. * We could squirrel the error to be returned into - * bio->bi_size, or similar. But that would be too ugly. */ + * bio->bi_iter.bi_size, or similar. But that would be too ugly. */ struct bio_and_error { struct bio *bio; int error; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 000abe2f105c..6a86fe7b730f 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3775,9 +3775,9 @@ static int __floppy_read_block_0(struct block_device *bdev) bio_vec.bv_len = size; bio_vec.bv_offset = 0; bio.bi_vcnt = 1; - bio.bi_size = size; + bio.bi_iter.bi_size = size; bio.bi_bdev = bdev; - bio.bi_sector = 0; + bio.bi_iter.bi_sector = 0; bio.bi_flags = (1 << BIO_QUIET); init_completion(&complete); bio.bi_private = &complete; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index c8dac7305244..f5e39989adde 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -415,7 +415,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) loff_t pos; int ret; - pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset; + pos = ((loff_t) bio->bi_iter.bi_sector << 9) + lo->lo_offset; if (bio_rw(bio) == WRITE) { struct file *file = lo->lo_backing_file; @@ -444,7 +444,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio) goto out; } ret = file->f_op->fallocate(file, mode, pos, - bio->bi_size); + bio->bi_iter.bi_size); if (unlikely(ret && ret != -EINVAL && ret != -EOPNOTSUPP)) ret = -EIO; diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 050c71267f14..69e9eb5a6b34 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -3993,7 +3993,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) } if (unlikely(bio->bi_rw & REQ_DISCARD)) { - bio_endio(bio, mtip_send_trim(dd, bio->bi_sector, + bio_endio(bio, mtip_send_trim(dd, bio->bi_iter.bi_sector, bio_sectors(bio))); return; } @@ -4006,7 +4006,8 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) if (bio_data_dir(bio) == WRITE && bio_sectors(bio) <= 64 && dd->unal_qdepth) { - if (bio->bi_sector % 8 != 0) /* Unaligned on 4k boundaries */ + if (bio->bi_iter.bi_sector % 8 != 0) + /* Unaligned on 4k boundaries */ unaligned = 1; else if (bio_sectors(bio) % 8 != 0) /* Aligned but not 4k/8k */ unaligned = 1; @@ -4035,7 +4036,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) /* Issue the read/write. */ mtip_hw_submit_io(dd, - bio->bi_sector, + bio->bi_iter.bi_sector, bio_sectors(bio), nents, tag, diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 26d03fa0bf26..53d217381873 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -468,7 +468,7 @@ static struct nvme_bio_pair *nvme_bio_split(struct bio *bio, int idx, { struct nvme_bio_pair *bp; - BUG_ON(len > bio->bi_size); + BUG_ON(len > bio->bi_iter.bi_size); BUG_ON(idx > bio->bi_vcnt); bp = kmalloc(sizeof(*bp), GFP_ATOMIC); @@ -479,11 +479,11 @@ static struct nvme_bio_pair *nvme_bio_split(struct bio *bio, int idx, bp->b1 = *bio; bp->b2 = *bio; - bp->b1.bi_size = len; - bp->b2.bi_size -= len; + bp->b1.bi_iter.bi_size = len; + bp->b2.bi_iter.bi_size -= len; bp->b1.bi_vcnt = idx; - bp->b2.bi_idx = idx; - bp->b2.bi_sector += len >> 9; + bp->b2.bi_iter.bi_idx = idx; + bp->b2.bi_iter.bi_sector += len >> 9; if (offset) { bp->bv1 = kmalloc(bio->bi_max_vecs * sizeof(struct bio_vec), @@ -552,11 +552,12 @@ static int nvme_map_bio(struct nvme_queue *nvmeq, struct nvme_iod *iod, { struct bio_vec *bvec, *bvprv = NULL; struct scatterlist *sg = NULL; - int i, length = 0, nsegs = 0, split_len = bio->bi_size; + int i, length = 0, nsegs = 0, split_len = bio->bi_iter.bi_size; if (nvmeq->dev->stripe_size) split_len = nvmeq->dev->stripe_size - - ((bio->bi_sector << 9) & (nvmeq->dev->stripe_size - 1)); + ((bio->bi_iter.bi_sector << 9) & + (nvmeq->dev->stripe_size - 1)); sg_init_table(iod->sg, psegs); bio_for_each_segment(bvec, bio, i) { @@ -584,7 +585,7 @@ static int nvme_map_bio(struct nvme_queue *nvmeq, struct nvme_iod *iod, if (dma_map_sg(nvmeq->q_dmadev, iod->sg, iod->nents, dma_dir) == 0) return -ENOMEM; - BUG_ON(length != bio->bi_size); + BUG_ON(length != bio->bi_iter.bi_size); return length; } @@ -608,8 +609,8 @@ static int nvme_submit_discard(struct nvme_queue *nvmeq, struct nvme_ns *ns, iod->npages = 0; range->cattr = cpu_to_le32(0); - range->nlb = cpu_to_le32(bio->bi_size >> ns->lba_shift); - range->slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_sector)); + range->nlb = cpu_to_le32(bio->bi_iter.bi_size >> ns->lba_shift); + range->slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_iter.bi_sector)); memset(cmnd, 0, sizeof(*cmnd)); cmnd->dsm.opcode = nvme_cmd_dsm; @@ -674,7 +675,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns, } result = -ENOMEM; - iod = nvme_alloc_iod(psegs, bio->bi_size, GFP_ATOMIC); + iod = nvme_alloc_iod(psegs, bio->bi_iter.bi_size, GFP_ATOMIC); if (!iod) goto nomem; iod->private = bio; @@ -723,7 +724,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns, cmnd->rw.nsid = cpu_to_le32(ns->ns_id); length = nvme_setup_prps(nvmeq->dev, &cmnd->common, iod, length, GFP_ATOMIC); - cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_sector)); + cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_iter.bi_sector)); cmnd->rw.length = cpu_to_le16((length >> ns->lba_shift) - 1); cmnd->rw.control = cpu_to_le16(control); cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index ff8668c5efb1..ce986bacf7b7 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -651,7 +651,7 @@ static struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s for (;;) { tmp = rb_entry(n, struct pkt_rb_node, rb_node); - if (s <= tmp->bio->bi_sector) + if (s <= tmp->bio->bi_iter.bi_sector) next = n->rb_left; else next = n->rb_right; @@ -660,12 +660,12 @@ static struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s n = next; } - if (s > tmp->bio->bi_sector) { + if (s > tmp->bio->bi_iter.bi_sector) { tmp = pkt_rbtree_next(tmp); if (!tmp) return NULL; } - BUG_ON(s > tmp->bio->bi_sector); + BUG_ON(s > tmp->bio->bi_iter.bi_sector); return tmp; } @@ -676,13 +676,13 @@ static void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *nod { struct rb_node **p = &pd->bio_queue.rb_node; struct rb_node *parent = NULL; - sector_t s = node->bio->bi_sector; + sector_t s = node->bio->bi_iter.bi_sector; struct pkt_rb_node *tmp; while (*p) { parent = *p; tmp = rb_entry(parent, struct pkt_rb_node, rb_node); - if (s < tmp->bio->bi_sector) + if (s < tmp->bio->bi_iter.bi_sector) p = &(*p)->rb_left; else p = &(*p)->rb_right; @@ -857,7 +857,8 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) spin_lock(&pd->iosched.lock); bio = bio_list_peek(&pd->iosched.write_queue); spin_unlock(&pd->iosched.lock); - if (bio && (bio->bi_sector == pd->iosched.last_write)) + if (bio && (bio->bi_iter.bi_sector == + pd->iosched.last_write)) need_write_seek = 0; if (need_write_seek && reads_queued) { if (atomic_read(&pd->cdrw.pending_bios) > 0) { @@ -888,7 +889,8 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd) continue; if (bio_data_dir(bio) == READ) - pd->iosched.successive_reads += bio->bi_size >> 10; + pd->iosched.successive_reads += + bio->bi_iter.bi_size >> 10; else { pd->iosched.successive_reads = 0; pd->iosched.last_write = bio_end_sector(bio); @@ -978,7 +980,7 @@ static void pkt_end_io_read(struct bio *bio, int err) pkt_dbg(2, pd, "bio=%p sec0=%llx sec=%llx err=%d\n", bio, (unsigned long long)pkt->sector, - (unsigned long long)bio->bi_sector, err); + (unsigned long long)bio->bi_iter.bi_sector, err); if (err) atomic_inc(&pkt->io_errors); @@ -1026,8 +1028,9 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) memset(written, 0, sizeof(written)); spin_lock(&pkt->lock); bio_list_for_each(bio, &pkt->orig_bios) { - int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9); - int num_frames = bio->bi_size / CD_FRAMESIZE; + int first_frame = (bio->bi_iter.bi_sector - pkt->sector) / + (CD_FRAMESIZE >> 9); + int num_frames = bio->bi_iter.bi_size / CD_FRAMESIZE; pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9); BUG_ON(first_frame < 0); BUG_ON(first_frame + num_frames > pkt->frames); @@ -1053,7 +1056,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt) bio = pkt->r_bios[f]; bio_reset(bio); - bio->bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9); + bio->bi_iter.bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9); bio->bi_bdev = pd->bdev; bio->bi_end_io = pkt_end_io_read; bio->bi_private = pkt; @@ -1150,8 +1153,8 @@ static int pkt_start_recovery(struct packet_data *pkt) bio_reset(pkt->bio); pkt->bio->bi_bdev = pd->bdev; pkt->bio->bi_rw = REQ_WRITE; - pkt->bio->bi_sector = new_sector; - pkt->bio->bi_size = pkt->frames * CD_FRAMESIZE; + pkt->bio->bi_iter.bi_sector = new_sector; + pkt->bio->bi_iter.bi_size = pkt->frames * CD_FRAMESIZE; pkt->bio->bi_vcnt = pkt->frames; pkt->bio->bi_end_io = pkt_end_io_packet_write; @@ -1213,7 +1216,7 @@ static int pkt_handle_queue(struct pktcdvd_device *pd) node = first_node; while (node) { bio = node->bio; - zone = get_zone(bio->bi_sector, pd); + zone = get_zone(bio->bi_iter.bi_sector, pd); list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) { if (p->sector == zone) { bio = NULL; @@ -1252,14 +1255,14 @@ try_next_bio: pkt_dbg(2, pd, "looking for zone %llx\n", (unsigned long long)zone); while ((node = pkt_rbtree_find(pd, zone)) != NULL) { bio = node->bio; - pkt_dbg(2, pd, "found zone=%llx\n", - (unsigned long long)get_zone(bio->bi_sector, pd)); - if (get_zone(bio->bi_sector, pd) != zone) + pkt_dbg(2, pd, "found zone=%llx\n", (unsigned long long) + get_zone(bio->bi_iter.bi_sector, pd)); + if (get_zone(bio->bi_iter.bi_sector, pd) != zone) break; pkt_rbtree_erase(pd, node); spin_lock(&pkt->lock); bio_list_add(&pkt->orig_bios, bio); - pkt->write_size += bio->bi_size / CD_FRAMESIZE; + pkt->write_size += bio->bi_iter.bi_size / CD_FRAMESIZE; spin_unlock(&pkt->lock); } /* check write congestion marks, and if bio_queue_size is @@ -1293,7 +1296,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt) struct bio_vec *bvec = pkt->w_bio->bi_io_vec; bio_reset(pkt->w_bio); - pkt->w_bio->bi_sector = pkt->sector; + pkt->w_bio->bi_iter.bi_sector = pkt->sector; pkt->w_bio->bi_bdev = pd->bdev; pkt->w_bio->bi_end_io = pkt_end_io_packet_write; pkt->w_bio->bi_private = pkt; @@ -2370,20 +2373,20 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) if (!test_bit(PACKET_WRITABLE, &pd->flags)) { pkt_notice(pd, "WRITE for ro device (%llu)\n", - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); goto end_io; } - if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) { + if (!bio->bi_iter.bi_size || (bio->bi_iter.bi_size % CD_FRAMESIZE)) { pkt_err(pd, "wrong bio size\n"); goto end_io; } blk_queue_bounce(q, &bio); - zone = get_zone(bio->bi_sector, pd); + zone = get_zone(bio->bi_iter.bi_sector, pd); pkt_dbg(2, pd, "start = %6llx stop = %6llx\n", - (unsigned long long)bio->bi_sector, + (unsigned long long)bio->bi_iter.bi_sector, (unsigned long long)bio_end_sector(bio)); /* Check if we have to split the bio */ @@ -2395,7 +2398,7 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) last_zone = get_zone(bio_end_sector(bio) - 1, pd); if (last_zone != zone) { BUG_ON(last_zone != zone + pd->settings.size); - first_sectors = last_zone - bio->bi_sector; + first_sectors = last_zone - bio->bi_iter.bi_sector; bp = bio_split(bio, first_sectors); BUG_ON(!bp); pkt_make_request(q, &bp->bio1); @@ -2417,7 +2420,8 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) if ((pkt->state == PACKET_WAITING_STATE) || (pkt->state == PACKET_READ_WAIT_STATE)) { bio_list_add(&pkt->orig_bios, bio); - pkt->write_size += bio->bi_size / CD_FRAMESIZE; + pkt->write_size += + bio->bi_iter.bi_size / CD_FRAMESIZE; if ((pkt->write_size >= pkt->frames) && (pkt->state == PACKET_WAITING_STATE)) { atomic_inc(&pkt->run_sm); diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index d754a88d7585..464be78a0836 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -104,7 +104,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u segs %u sectors from %lu\n", __func__, __LINE__, i, bio_segments(iter.bio), - bio_sectors(iter.bio), iter.bio->bi_sector); + bio_sectors(iter.bio), iter.bio->bi_iter.bi_sector); size = bvec->bv_len; buf = bvec_kmap_irq(bvec, &flags); diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 06a2e53e5f37..320bbfc9b902 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -553,7 +553,7 @@ static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev, struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); int write = bio_data_dir(bio) == WRITE; const char *op = write ? "write" : "read"; - loff_t offset = bio->bi_sector << 9; + loff_t offset = bio->bi_iter.bi_sector << 9; int error = 0; struct bio_vec *bvec; unsigned int i; diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index cb1db2979d3d..a8f4fe2d4d1b 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1183,14 +1183,14 @@ static struct bio *bio_clone_range(struct bio *bio_src, /* Handle the easy case for the caller */ - if (!offset && len == bio_src->bi_size) + if (!offset && len == bio_src->bi_iter.bi_size) return bio_clone(bio_src, gfpmask); if (WARN_ON_ONCE(!len)) return NULL; - if (WARN_ON_ONCE(len > bio_src->bi_size)) + if (WARN_ON_ONCE(len > bio_src->bi_iter.bi_size)) return NULL; - if (WARN_ON_ONCE(offset > bio_src->bi_size - len)) + if (WARN_ON_ONCE(offset > bio_src->bi_iter.bi_size - len)) return NULL; /* Find first affected segment... */ @@ -1220,7 +1220,8 @@ static struct bio *bio_clone_range(struct bio *bio_src, return NULL; /* ENOMEM */ bio->bi_bdev = bio_src->bi_bdev; - bio->bi_sector = bio_src->bi_sector + (offset >> SECTOR_SHIFT); + bio->bi_iter.bi_sector = bio_src->bi_iter.bi_sector + + (offset >> SECTOR_SHIFT); bio->bi_rw = bio_src->bi_rw; bio->bi_flags |= 1 << BIO_CLONED; @@ -1239,8 +1240,7 @@ static struct bio *bio_clone_range(struct bio *bio_src, } bio->bi_vcnt = vcnt; - bio->bi_size = len; - bio->bi_idx = 0; + bio->bi_iter.bi_size = len; return bio; } @@ -1271,7 +1271,7 @@ static struct bio *bio_chain_clone_range(struct bio **bio_src, /* Build up a chain of clone bios up to the limit */ - if (!bi || off >= bi->bi_size || !len) + if (!bi || off >= bi->bi_iter.bi_size || !len) return NULL; /* Nothing to clone */ end = &chain; @@ -1283,7 +1283,7 @@ static struct bio *bio_chain_clone_range(struct bio **bio_src, rbd_warn(NULL, "bio_chain exhausted with %u left", len); goto out_err; /* EINVAL; ran out of bio's */ } - bi_size = min_t(unsigned int, bi->bi_size - off, len); + bi_size = min_t(unsigned int, bi->bi_iter.bi_size - off, len); bio = bio_clone_range(bi, off, bi_size, gfpmask); if (!bio) goto out_err; /* ENOMEM */ @@ -1292,7 +1292,7 @@ static struct bio *bio_chain_clone_range(struct bio **bio_src, end = &bio->bi_next; off += bi_size; - if (off == bi->bi_size) { + if (off == bi->bi_iter.bi_size) { bi = bi->bi_next; off = 0; } @@ -2186,7 +2186,8 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request, if (type == OBJ_REQUEST_BIO) { bio_list = data_desc; - rbd_assert(img_offset == bio_list->bi_sector << SECTOR_SHIFT); + rbd_assert(img_offset == + bio_list->bi_iter.bi_sector << SECTOR_SHIFT); } else { rbd_assert(type == OBJ_REQUEST_PAGES); pages = data_desc; diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c index 2284f5d3a54a..2839d37e5af7 100644 --- a/drivers/block/rsxx/dev.c +++ b/drivers/block/rsxx/dev.c @@ -174,7 +174,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio) if (!card) goto req_err; - if (bio->bi_sector + (bio->bi_size >> 9) > get_capacity(card->gendisk)) + if (bio_end_sector(bio) > get_capacity(card->gendisk)) goto req_err; if (unlikely(card->halt)) { @@ -187,7 +187,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio) goto req_err; } - if (bio->bi_size == 0) { + if (bio->bi_iter.bi_size == 0) { dev_err(CARD_TO_DEV(card), "size zero BIO!\n"); goto req_err; } @@ -208,7 +208,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio) dev_dbg(CARD_TO_DEV(card), "BIO[%c]: meta: %p addr8: x%llx size: %d\n", bio_data_dir(bio) ? 'W' : 'R', bio_meta, - (u64)bio->bi_sector << 9, bio->bi_size); + (u64)bio->bi_iter.bi_sector << 9, bio->bi_iter.bi_size); st = rsxx_dma_queue_bio(card, bio, &bio_meta->pending_dmas, bio_dma_done_cb, bio_meta); diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index fc88ba3e1bd2..3716633be3c2 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -696,7 +696,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, int st; int i; - addr8 = bio->bi_sector << 9; /* sectors are 512 bytes */ + addr8 = bio->bi_iter.bi_sector << 9; /* sectors are 512 bytes */ atomic_set(n_dmas, 0); for (i = 0; i < card->n_targets; i++) { @@ -705,7 +705,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, } if (bio->bi_rw & REQ_DISCARD) { - bv_len = bio->bi_size; + bv_len = bio->bi_iter.bi_size; while (bv_len > 0) { tgt = rsxx_get_dma_tgt(card, addr8); diff --git a/drivers/block/umem.c b/drivers/block/umem.c index ad70868f8a96..dab4f1afeae9 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -352,8 +352,8 @@ static int add_bio(struct cardinfo *card) bio = card->currentbio; if (!bio && card->bio) { card->currentbio = card->bio; - card->current_idx = card->bio->bi_idx; - card->current_sector = card->bio->bi_sector; + card->current_idx = card->bio->bi_iter.bi_idx; + card->current_sector = card->bio->bi_iter.bi_sector; card->bio = card->bio->bi_next; if (card->bio == NULL) card->biotail = &card->bio; @@ -451,7 +451,7 @@ static void process_page(unsigned long data) if (page->idx >= bio->bi_vcnt) { page->bio = bio->bi_next; if (page->bio) - page->idx = page->bio->bi_idx; + page->idx = page->bio->bi_iter.bi_idx; } pci_unmap_page(card->dev, desc->data_dma_handle, @@ -532,7 +532,8 @@ static void mm_make_request(struct request_queue *q, struct bio *bio) { struct cardinfo *card = q->queuedata; pr_debug("mm_make_request %llu %u\n", - (unsigned long long)bio->bi_sector, bio->bi_size); + (unsigned long long)bio->bi_iter.bi_sector, + bio->bi_iter.bi_size); spin_lock_irq(&card->lock); *card->biotail = bio; diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 6620b73d0490..4b97b86da926 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -1257,7 +1257,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, bio->bi_bdev = preq.bdev; bio->bi_private = pending_req; bio->bi_end_io = end_block_io_op; - bio->bi_sector = preq.sector_number; + bio->bi_iter.bi_sector = preq.sector_number; } preq.sector_number += seg[i].nsec; diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 432db1b59b00..80e86307dd4b 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1547,7 +1547,7 @@ static int blkif_recover(struct blkfront_info *info) for (i = 0; i < pending; i++) { offset = (i * segs * PAGE_SIZE) >> 9; size = min((unsigned int)(segs * PAGE_SIZE) >> 9, - (unsigned int)(bio->bi_size >> 9) - offset); + (unsigned int)bio_sectors(bio) - offset); cloned_bio = bio_clone(bio, GFP_NOIO); BUG_ON(cloned_bio == NULL); bio_trim(cloned_bio, offset, size); diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 5e2765aadce1..038a6d2aced3 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -299,7 +299,7 @@ void bch_btree_node_read(struct btree *b) bio = bch_bbio_alloc(b->c); bio->bi_rw = REQ_META|READ_SYNC; - bio->bi_size = KEY_SIZE(&b->key) << 9; + bio->bi_iter.bi_size = KEY_SIZE(&b->key) << 9; bio->bi_end_io = btree_node_read_endio; bio->bi_private = &cl; @@ -395,7 +395,7 @@ static void do_btree_node_write(struct btree *b) b->bio->bi_end_io = btree_node_write_endio; b->bio->bi_private = cl; b->bio->bi_rw = REQ_META|WRITE_SYNC|REQ_FUA; - b->bio->bi_size = set_blocks(i, b->c) * block_bytes(b->c); + b->bio->bi_iter.bi_size = set_blocks(i, b->c) * block_bytes(b->c); bch_bio_map(b->bio, i); /* diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c index 264fcfbd6290..92b3fd468a03 100644 --- a/drivers/md/bcache/debug.c +++ b/drivers/md/bcache/debug.c @@ -195,7 +195,7 @@ void bch_data_verify(struct cached_dev *dc, struct bio *bio) dc->disk.c, "verify failed at dev %s sector %llu", bdevname(dc->bdev, name), - (uint64_t) bio->bi_sector); + (uint64_t) bio->bi_iter.bi_sector); kunmap_atomic(p1); } diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index 9056632995b1..cc4ba2da5fb6 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -21,18 +21,18 @@ static void bch_bi_idx_hack_endio(struct bio *bio, int error) static void bch_generic_make_request_hack(struct bio *bio) { - if (bio->bi_idx) { + if (bio->bi_iter.bi_idx) { struct bio *clone = bio_alloc(GFP_NOIO, bio_segments(bio)); memcpy(clone->bi_io_vec, bio_iovec(bio), bio_segments(bio) * sizeof(struct bio_vec)); - clone->bi_sector = bio->bi_sector; + clone->bi_iter.bi_sector = bio->bi_iter.bi_sector; clone->bi_bdev = bio->bi_bdev; clone->bi_rw = bio->bi_rw; clone->bi_vcnt = bio_segments(bio); - clone->bi_size = bio->bi_size; + clone->bi_iter.bi_size = bio->bi_iter.bi_size; clone->bi_private = bio; clone->bi_end_io = bch_bi_idx_hack_endio; @@ -72,7 +72,7 @@ static void bch_generic_make_request_hack(struct bio *bio) struct bio *bch_bio_split(struct bio *bio, int sectors, gfp_t gfp, struct bio_set *bs) { - unsigned idx = bio->bi_idx, vcnt = 0, nbytes = sectors << 9; + unsigned idx = bio->bi_iter.bi_idx, vcnt = 0, nbytes = sectors << 9; struct bio_vec *bv; struct bio *ret = NULL; @@ -90,7 +90,7 @@ struct bio *bch_bio_split(struct bio *bio, int sectors, } bio_for_each_segment(bv, bio, idx) { - vcnt = idx - bio->bi_idx; + vcnt = idx - bio->bi_iter.bi_idx; if (!nbytes) { ret = bio_alloc_bioset(gfp, vcnt, bs); @@ -119,15 +119,15 @@ struct bio *bch_bio_split(struct bio *bio, int sectors, } out: ret->bi_bdev = bio->bi_bdev; - ret->bi_sector = bio->bi_sector; - ret->bi_size = sectors << 9; + ret->bi_iter.bi_sector = bio->bi_iter.bi_sector; + ret->bi_iter.bi_size = sectors << 9; ret->bi_rw = bio->bi_rw; ret->bi_vcnt = vcnt; ret->bi_max_vecs = vcnt; - bio->bi_sector += sectors; - bio->bi_size -= sectors << 9; - bio->bi_idx = idx; + bio->bi_iter.bi_sector += sectors; + bio->bi_iter.bi_size -= sectors << 9; + bio->bi_iter.bi_idx = idx; if (bio_integrity(bio)) { if (bio_integrity_clone(ret, bio, gfp)) { @@ -162,7 +162,7 @@ static unsigned bch_bio_max_sectors(struct bio *bio) bio_for_each_segment(bv, bio, i) { struct bvec_merge_data bvm = { .bi_bdev = bio->bi_bdev, - .bi_sector = bio->bi_sector, + .bi_sector = bio->bi_iter.bi_sector, .bi_size = ret << 9, .bi_rw = bio->bi_rw, }; @@ -272,8 +272,8 @@ void __bch_submit_bbio(struct bio *bio, struct cache_set *c) { struct bbio *b = container_of(bio, struct bbio, bio); - bio->bi_sector = PTR_OFFSET(&b->key, 0); - bio->bi_bdev = PTR_CACHE(c, &b->key, 0)->bdev; + bio->bi_iter.bi_sector = PTR_OFFSET(&b->key, 0); + bio->bi_bdev = PTR_CACHE(c, &b->key, 0)->bdev; b->submit_time_us = local_clock_us(); closure_bio_submit(bio, bio->bi_private, PTR_CACHE(c, &b->key, 0)); diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index ecdaa671bd50..7eafdf09a0ae 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -51,10 +51,10 @@ reread: left = ca->sb.bucket_size - offset; len = min_t(unsigned, left, PAGE_SECTORS * 8); bio_reset(bio); - bio->bi_sector = bucket + offset; + bio->bi_iter.bi_sector = bucket + offset; bio->bi_bdev = ca->bdev; bio->bi_rw = READ; - bio->bi_size = len << 9; + bio->bi_iter.bi_size = len << 9; bio->bi_end_io = journal_read_endio; bio->bi_private = &cl; @@ -437,13 +437,13 @@ static void do_journal_discard(struct cache *ca) atomic_set(&ja->discard_in_flight, DISCARD_IN_FLIGHT); bio_init(bio); - bio->bi_sector = bucket_to_sector(ca->set, + bio->bi_iter.bi_sector = bucket_to_sector(ca->set, ca->sb.d[ja->discard_idx]); bio->bi_bdev = ca->bdev; bio->bi_rw = REQ_WRITE|REQ_DISCARD; bio->bi_max_vecs = 1; bio->bi_io_vec = bio->bi_inline_vecs; - bio->bi_size = bucket_bytes(ca); + bio->bi_iter.bi_size = bucket_bytes(ca); bio->bi_end_io = journal_discard_endio; closure_get(&ca->set->cl); @@ -608,10 +608,10 @@ static void journal_write_unlocked(struct closure *cl) atomic_long_add(sectors, &ca->meta_sectors_written); bio_reset(bio); - bio->bi_sector = PTR_OFFSET(k, i); + bio->bi_iter.bi_sector = PTR_OFFSET(k, i); bio->bi_bdev = ca->bdev; bio->bi_rw = REQ_WRITE|REQ_SYNC|REQ_META|REQ_FLUSH|REQ_FUA; - bio->bi_size = sectors << 9; + bio->bi_iter.bi_size = sectors << 9; bio->bi_end_io = journal_write_endio; bio->bi_private = w; diff --git a/drivers/md/bcache/movinggc.c b/drivers/md/bcache/movinggc.c index 7c1275e66025..581f95df8265 100644 --- a/drivers/md/bcache/movinggc.c +++ b/drivers/md/bcache/movinggc.c @@ -82,7 +82,7 @@ static void moving_init(struct moving_io *io) bio_get(bio); bio_set_prio(bio, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)); - bio->bi_size = KEY_SIZE(&io->w->key) << 9; + bio->bi_iter.bi_size = KEY_SIZE(&io->w->key) << 9; bio->bi_max_vecs = DIV_ROUND_UP(KEY_SIZE(&io->w->key), PAGE_SECTORS); bio->bi_private = &io->cl; @@ -98,7 +98,7 @@ static void write_moving(struct closure *cl) if (!op->error) { moving_init(io); - io->bio.bio.bi_sector = KEY_START(&io->w->key); + io->bio.bio.bi_iter.bi_sector = KEY_START(&io->w->key); op->write_prio = 1; op->bio = &io->bio.bio; diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 78bab4154e97..47a9bbc75124 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -261,7 +261,7 @@ static void bch_data_invalidate(struct closure *cl) struct bio *bio = op->bio; pr_debug("invalidating %i sectors from %llu", - bio_sectors(bio), (uint64_t) bio->bi_sector); + bio_sectors(bio), (uint64_t) bio->bi_iter.bi_sector); while (bio_sectors(bio)) { unsigned sectors = min(bio_sectors(bio), @@ -270,11 +270,11 @@ static void bch_data_invalidate(struct closure *cl) if (bch_keylist_realloc(&op->insert_keys, 0, op->c)) goto out; - bio->bi_sector += sectors; - bio->bi_size -= sectors << 9; + bio->bi_iter.bi_sector += sectors; + bio->bi_iter.bi_size -= sectors << 9; bch_keylist_add(&op->insert_keys, - &KEY(op->inode, bio->bi_sector, sectors)); + &KEY(op->inode, bio->bi_iter.bi_sector, sectors)); } op->insert_data_done = true; @@ -364,7 +364,7 @@ static void bch_data_insert_start(struct closure *cl) k = op->insert_keys.top; bkey_init(k); SET_KEY_INODE(k, op->inode); - SET_KEY_OFFSET(k, bio->bi_sector); + SET_KEY_OFFSET(k, bio->bi_iter.bi_sector); if (!bch_alloc_sectors(op->c, k, bio_sectors(bio), op->write_point, op->write_prio, @@ -522,7 +522,7 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio) (bio->bi_rw & REQ_WRITE))) goto skip; - if (bio->bi_sector & (c->sb.block_size - 1) || + if (bio->bi_iter.bi_sector & (c->sb.block_size - 1) || bio_sectors(bio) & (c->sb.block_size - 1)) { pr_debug("skipping unaligned io"); goto skip; @@ -546,8 +546,8 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio) spin_lock(&dc->io_lock); - hlist_for_each_entry(i, iohash(dc, bio->bi_sector), hash) - if (i->last == bio->bi_sector && + hlist_for_each_entry(i, iohash(dc, bio->bi_iter.bi_sector), hash) + if (i->last == bio->bi_iter.bi_sector && time_before(jiffies, i->jiffies)) goto found; @@ -556,8 +556,8 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio) add_sequential(task); i->sequential = 0; found: - if (i->sequential + bio->bi_size > i->sequential) - i->sequential += bio->bi_size; + if (i->sequential + bio->bi_iter.bi_size > i->sequential) + i->sequential += bio->bi_iter.bi_size; i->last = bio_end_sector(bio); i->jiffies = jiffies + msecs_to_jiffies(5000); @@ -650,15 +650,15 @@ static int cache_lookup_fn(struct btree_op *op, struct btree *b, struct bkey *k) struct bkey *bio_key; unsigned ptr; - if (bkey_cmp(k, &KEY(s->iop.inode, bio->bi_sector, 0)) <= 0) + if (bkey_cmp(k, &KEY(s->iop.inode, bio->bi_iter.bi_sector, 0)) <= 0) return MAP_CONTINUE; if (KEY_INODE(k) != s->iop.inode || - KEY_START(k) > bio->bi_sector) { + KEY_START(k) > bio->bi_iter.bi_sector) { unsigned bio_sectors = bio_sectors(bio); unsigned sectors = KEY_INODE(k) == s->iop.inode ? min_t(uint64_t, INT_MAX, - KEY_START(k) - bio->bi_sector) + KEY_START(k) - bio->bi_iter.bi_sector) : INT_MAX; int ret = s->d->cache_miss(b, s, bio, sectors); @@ -681,13 +681,13 @@ static int cache_lookup_fn(struct btree_op *op, struct btree *b, struct bkey *k) s->read_dirty_data = true; n = bch_bio_split(bio, min_t(uint64_t, INT_MAX, - KEY_OFFSET(k) - bio->bi_sector), + KEY_OFFSET(k) - bio->bi_iter.bi_sector), GFP_NOIO, s->d->bio_split); bio_key = &container_of(n, struct bbio, bio)->key; bch_bkey_copy_single_ptr(bio_key, k, ptr); - bch_cut_front(&KEY(s->iop.inode, n->bi_sector, 0), bio_key); + bch_cut_front(&KEY(s->iop.inode, n->bi_iter.bi_sector, 0), bio_key); bch_cut_back(&KEY(s->iop.inode, bio_end_sector(n), 0), bio_key); n->bi_end_io = bch_cache_read_endio; @@ -714,7 +714,7 @@ static void cache_lookup(struct closure *cl) struct bio *bio = &s->bio.bio; int ret = bch_btree_map_keys(&s->op, s->iop.c, - &KEY(s->iop.inode, bio->bi_sector, 0), + &KEY(s->iop.inode, bio->bi_iter.bi_sector, 0), cache_lookup_fn, MAP_END_KEY); if (ret == -EAGAIN) continue_at(cl, cache_lookup, bcache_wq); @@ -872,9 +872,9 @@ static void cached_dev_read_done(struct closure *cl) if (s->iop.bio) { bio_reset(s->iop.bio); - s->iop.bio->bi_sector = s->cache_miss->bi_sector; + s->iop.bio->bi_iter.bi_sector = s->cache_miss->bi_iter.bi_sector; s->iop.bio->bi_bdev = s->cache_miss->bi_bdev; - s->iop.bio->bi_size = s->insert_bio_sectors << 9; + s->iop.bio->bi_iter.bi_size = s->insert_bio_sectors << 9; bch_bio_map(s->iop.bio, NULL); bio_copy_data(s->cache_miss, s->iop.bio); @@ -937,7 +937,7 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s, s->insert_bio_sectors = min(sectors, bio_sectors(bio) + reada); s->iop.replace_key = KEY(s->iop.inode, - bio->bi_sector + s->insert_bio_sectors, + bio->bi_iter.bi_sector + s->insert_bio_sectors, s->insert_bio_sectors); ret = bch_btree_insert_check_key(b, &s->op, &s->iop.replace_key); @@ -957,9 +957,9 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s, if (!cache_bio) goto out_submit; - cache_bio->bi_sector = miss->bi_sector; - cache_bio->bi_bdev = miss->bi_bdev; - cache_bio->bi_size = s->insert_bio_sectors << 9; + cache_bio->bi_iter.bi_sector = miss->bi_iter.bi_sector; + cache_bio->bi_bdev = miss->bi_bdev; + cache_bio->bi_iter.bi_size = s->insert_bio_sectors << 9; cache_bio->bi_end_io = request_endio; cache_bio->bi_private = &s->cl; @@ -1009,7 +1009,7 @@ static void cached_dev_write(struct cached_dev *dc, struct search *s) { struct closure *cl = &s->cl; struct bio *bio = &s->bio.bio; - struct bkey start = KEY(dc->disk.id, bio->bi_sector, 0); + struct bkey start = KEY(dc->disk.id, bio->bi_iter.bi_sector, 0); struct bkey end = KEY(dc->disk.id, bio_end_sector(bio), 0); bch_keybuf_check_overlapping(&s->iop.c->moving_gc_keys, &start, &end); @@ -1104,13 +1104,13 @@ static void cached_dev_make_request(struct request_queue *q, struct bio *bio) part_stat_unlock(); bio->bi_bdev = dc->bdev; - bio->bi_sector += dc->sb.data_offset; + bio->bi_iter.bi_sector += dc->sb.data_offset; if (cached_dev_get(dc)) { s = search_alloc(bio, d); trace_bcache_request_start(s->d, bio); - if (!bio->bi_size) { + if (!bio->bi_iter.bi_size) { /* * can't call bch_journal_meta from under * generic_make_request @@ -1197,9 +1197,9 @@ static int flash_dev_cache_miss(struct btree *b, struct search *s, sectors -= j; } - bio_advance(bio, min(sectors << 9, bio->bi_size)); + bio_advance(bio, min(sectors << 9, bio->bi_iter.bi_size)); - if (!bio->bi_size) + if (!bio->bi_iter.bi_size) return MAP_DONE; return MAP_CONTINUE; @@ -1233,7 +1233,7 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio) trace_bcache_request_start(s->d, bio); - if (!bio->bi_size) { + if (!bio->bi_iter.bi_size) { /* * can't call bch_journal_meta from under * generic_make_request @@ -1243,7 +1243,7 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio) bcache_wq); } else if (rw) { bch_keybuf_check_overlapping(&s->iop.c->moving_gc_keys, - &KEY(d->id, bio->bi_sector, 0), + &KEY(d->id, bio->bi_iter.bi_sector, 0), &KEY(d->id, bio_end_sector(bio), 0)); s->iop.bypass = (bio->bi_rw & REQ_DISCARD) != 0; diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 1d9ee67d14ec..60fb6044b953 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -233,9 +233,9 @@ static void __write_super(struct cache_sb *sb, struct bio *bio) struct cache_sb *out = page_address(bio->bi_io_vec[0].bv_page); unsigned i; - bio->bi_sector = SB_SECTOR; - bio->bi_rw = REQ_SYNC|REQ_META; - bio->bi_size = SB_SIZE; + bio->bi_iter.bi_sector = SB_SECTOR; + bio->bi_rw = REQ_SYNC|REQ_META; + bio->bi_iter.bi_size = SB_SIZE; bch_bio_map(bio, NULL); out->offset = cpu_to_le64(sb->offset); @@ -347,7 +347,7 @@ static void uuid_io(struct cache_set *c, unsigned long rw, struct bio *bio = bch_bbio_alloc(c); bio->bi_rw = REQ_SYNC|REQ_META|rw; - bio->bi_size = KEY_SIZE(k) << 9; + bio->bi_iter.bi_size = KEY_SIZE(k) << 9; bio->bi_end_io = uuid_endio; bio->bi_private = cl; @@ -503,10 +503,10 @@ static void prio_io(struct cache *ca, uint64_t bucket, unsigned long rw) closure_init_stack(cl); - bio->bi_sector = bucket * ca->sb.bucket_size; - bio->bi_bdev = ca->bdev; - bio->bi_rw = REQ_SYNC|REQ_META|rw; - bio->bi_size = bucket_bytes(ca); + bio->bi_iter.bi_sector = bucket * ca->sb.bucket_size; + bio->bi_bdev = ca->bdev; + bio->bi_rw = REQ_SYNC|REQ_META|rw; + bio->bi_iter.bi_size = bucket_bytes(ca); bio->bi_end_io = prio_endio; bio->bi_private = ca; diff --git a/drivers/md/bcache/util.c b/drivers/md/bcache/util.c index 462214eeacbe..c57621e49dc0 100644 --- a/drivers/md/bcache/util.c +++ b/drivers/md/bcache/util.c @@ -218,10 +218,10 @@ uint64_t bch_next_delay(struct bch_ratelimit *d, uint64_t done) void bch_bio_map(struct bio *bio, void *base) { - size_t size = bio->bi_size; + size_t size = bio->bi_iter.bi_size; struct bio_vec *bv = bio->bi_io_vec; - BUG_ON(!bio->bi_size); + BUG_ON(!bio->bi_iter.bi_size); BUG_ON(bio->bi_vcnt); bv->bv_offset = base ? ((unsigned long) base) % PAGE_SIZE : 0; diff --git a/drivers/md/bcache/writeback.c b/drivers/md/bcache/writeback.c index 99053b1251be..04657e93f4fd 100644 --- a/drivers/md/bcache/writeback.c +++ b/drivers/md/bcache/writeback.c @@ -113,7 +113,7 @@ static void dirty_init(struct keybuf_key *w) if (!io->dc->writeback_percent) bio_set_prio(bio, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)); - bio->bi_size = KEY_SIZE(&w->key) << 9; + bio->bi_iter.bi_size = KEY_SIZE(&w->key) << 9; bio->bi_max_vecs = DIV_ROUND_UP(KEY_SIZE(&w->key), PAGE_SECTORS); bio->bi_private = w; bio->bi_io_vec = bio->bi_inline_vecs; @@ -186,7 +186,7 @@ static void write_dirty(struct closure *cl) dirty_init(w); io->bio.bi_rw = WRITE; - io->bio.bi_sector = KEY_START(&w->key); + io->bio.bi_iter.bi_sector = KEY_START(&w->key); io->bio.bi_bdev = io->dc->bdev; io->bio.bi_end_io = dirty_endio; @@ -255,7 +255,7 @@ static void read_dirty(struct cached_dev *dc) io->dc = dc; dirty_init(w); - io->bio.bi_sector = PTR_OFFSET(&w->key, 0); + io->bio.bi_iter.bi_sector = PTR_OFFSET(&w->key, 0); io->bio.bi_bdev = PTR_CACHE(dc->disk.c, &w->key, 0)->bdev; io->bio.bi_rw = READ; diff --git a/drivers/md/bcache/writeback.h b/drivers/md/bcache/writeback.h index c9ddcf4614b9..e2f8598937ac 100644 --- a/drivers/md/bcache/writeback.h +++ b/drivers/md/bcache/writeback.h @@ -50,7 +50,7 @@ static inline bool should_writeback(struct cached_dev *dc, struct bio *bio, return false; if (dc->partial_stripes_expensive && - bcache_dev_stripe_dirty(dc, bio->bi_sector, + bcache_dev_stripe_dirty(dc, bio->bi_iter.bi_sector, bio_sectors(bio))) return true; diff --git a/drivers/md/dm-bio-record.h b/drivers/md/dm-bio-record.h index 3a8cfa2645c7..5ace48ee9f58 100644 --- a/drivers/md/dm-bio-record.h +++ b/drivers/md/dm-bio-record.h @@ -40,10 +40,10 @@ static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio) { unsigned i; - bd->bi_sector = bio->bi_sector; + bd->bi_sector = bio->bi_iter.bi_sector; bd->bi_bdev = bio->bi_bdev; - bd->bi_size = bio->bi_size; - bd->bi_idx = bio->bi_idx; + bd->bi_size = bio->bi_iter.bi_size; + bd->bi_idx = bio->bi_iter.bi_idx; bd->bi_flags = bio->bi_flags; for (i = 0; i < bio->bi_vcnt; i++) { @@ -56,10 +56,10 @@ static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio) { unsigned i; - bio->bi_sector = bd->bi_sector; + bio->bi_iter.bi_sector = bd->bi_sector; bio->bi_bdev = bd->bi_bdev; - bio->bi_size = bd->bi_size; - bio->bi_idx = bd->bi_idx; + bio->bi_iter.bi_size = bd->bi_size; + bio->bi_iter.bi_idx = bd->bi_idx; bio->bi_flags = bd->bi_flags; for (i = 0; i < bio->bi_vcnt; i++) { diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c index 173cbb20d104..4113b6044b80 100644 --- a/drivers/md/dm-bufio.c +++ b/drivers/md/dm-bufio.c @@ -538,7 +538,7 @@ static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block, bio_init(&b->bio); b->bio.bi_io_vec = b->bio_vec; b->bio.bi_max_vecs = DM_BUFIO_INLINE_VECS; - b->bio.bi_sector = block << b->c->sectors_per_block_bits; + b->bio.bi_iter.bi_sector = block << b->c->sectors_per_block_bits; b->bio.bi_bdev = b->c->bdev; b->bio.bi_end_io = end_io; diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c index 416b7b752a6e..bfba97dcde2d 100644 --- a/drivers/md/dm-cache-policy-mq.c +++ b/drivers/md/dm-cache-policy-mq.c @@ -72,7 +72,7 @@ static enum io_pattern iot_pattern(struct io_tracker *t) static void iot_update_stats(struct io_tracker *t, struct bio *bio) { - if (bio->bi_sector == from_oblock(t->last_end_oblock) + 1) + if (bio->bi_iter.bi_sector == from_oblock(t->last_end_oblock) + 1) t->nr_seq_samples++; else { /* @@ -87,7 +87,7 @@ static void iot_update_stats(struct io_tracker *t, struct bio *bio) t->nr_rand_samples++; } - t->last_end_oblock = to_oblock(bio->bi_sector + bio_sectors(bio) - 1); + t->last_end_oblock = to_oblock(bio_end_sector(bio) - 1); } static void iot_check_for_pattern_switch(struct io_tracker *t) diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 9efcf1059b99..86f9c83eb30c 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -664,15 +664,17 @@ static void remap_to_origin(struct cache *cache, struct bio *bio) static void remap_to_cache(struct cache *cache, struct bio *bio, dm_cblock_t cblock) { - sector_t bi_sector = bio->bi_sector; + sector_t bi_sector = bio->bi_iter.bi_sector; bio->bi_bdev = cache->cache_dev->bdev; if (!block_size_is_power_of_two(cache)) - bio->bi_sector = (from_cblock(cblock) * cache->sectors_per_block) + - sector_div(bi_sector, cache->sectors_per_block); + bio->bi_iter.bi_sector = + (from_cblock(cblock) * cache->sectors_per_block) + + sector_div(bi_sector, cache->sectors_per_block); else - bio->bi_sector = (from_cblock(cblock) << cache->sectors_per_block_shift) | - (bi_sector & (cache->sectors_per_block - 1)); + bio->bi_iter.bi_sector = + (from_cblock(cblock) << cache->sectors_per_block_shift) | + (bi_sector & (cache->sectors_per_block - 1)); } static void check_if_tick_bio_needed(struct cache *cache, struct bio *bio) @@ -712,7 +714,7 @@ static void remap_to_cache_dirty(struct cache *cache, struct bio *bio, static dm_oblock_t get_bio_block(struct cache *cache, struct bio *bio) { - sector_t block_nr = bio->bi_sector; + sector_t block_nr = bio->bi_iter.bi_sector; if (!block_size_is_power_of_two(cache)) (void) sector_div(block_nr, cache->sectors_per_block); @@ -1027,7 +1029,7 @@ static void issue_overwrite(struct dm_cache_migration *mg, struct bio *bio) static bool bio_writes_complete_block(struct cache *cache, struct bio *bio) { return (bio_data_dir(bio) == WRITE) && - (bio->bi_size == (cache->sectors_per_block << SECTOR_SHIFT)); + (bio->bi_iter.bi_size == (cache->sectors_per_block << SECTOR_SHIFT)); } static void avoid_copy(struct dm_cache_migration *mg) @@ -1252,7 +1254,7 @@ static void process_flush_bio(struct cache *cache, struct bio *bio) size_t pb_data_size = get_per_bio_data_size(cache); struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size); - BUG_ON(bio->bi_size); + BUG_ON(bio->bi_iter.bi_size); if (!pb->req_nr) remap_to_origin(cache, bio); else @@ -1275,9 +1277,9 @@ static void process_flush_bio(struct cache *cache, struct bio *bio) */ static void process_discard_bio(struct cache *cache, struct bio *bio) { - dm_block_t start_block = dm_sector_div_up(bio->bi_sector, + dm_block_t start_block = dm_sector_div_up(bio->bi_iter.bi_sector, cache->discard_block_size); - dm_block_t end_block = bio->bi_sector + bio_sectors(bio); + dm_block_t end_block = bio_end_sector(bio); dm_block_t b; end_block = block_div(end_block, cache->discard_block_size); diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 81b0fa660452..1e2e5465d28e 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -828,8 +828,8 @@ static void crypt_convert_init(struct crypt_config *cc, ctx->bio_out = bio_out; ctx->offset_in = 0; ctx->offset_out = 0; - ctx->idx_in = bio_in ? bio_in->bi_idx : 0; - ctx->idx_out = bio_out ? bio_out->bi_idx : 0; + ctx->idx_in = bio_in ? bio_in->bi_iter.bi_idx : 0; + ctx->idx_out = bio_out ? bio_out->bi_iter.bi_idx : 0; ctx->cc_sector = sector + cc->iv_offset; init_completion(&ctx->restart); } @@ -1021,7 +1021,7 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size, size -= len; } - if (!clone->bi_size) { + if (!clone->bi_iter.bi_size) { bio_put(clone); return NULL; } @@ -1161,7 +1161,7 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp) crypt_inc_pending(io); clone_init(io, clone); - clone->bi_sector = cc->start + io->sector; + clone->bi_iter.bi_sector = cc->start + io->sector; generic_make_request(clone); return 0; @@ -1209,7 +1209,7 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async) /* crypt_convert should have filled the clone bio */ BUG_ON(io->ctx.idx_out < clone->bi_vcnt); - clone->bi_sector = cc->start + io->sector; + clone->bi_iter.bi_sector = cc->start + io->sector; if (async) kcryptd_queue_io(io); @@ -1224,7 +1224,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) struct dm_crypt_io *new_io; int crypt_finished; unsigned out_of_pages = 0; - unsigned remaining = io->base_bio->bi_size; + unsigned remaining = io->base_bio->bi_iter.bi_size; sector_t sector = io->sector; int r; @@ -1248,7 +1248,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) io->ctx.bio_out = clone; io->ctx.idx_out = 0; - remaining -= clone->bi_size; + remaining -= clone->bi_iter.bi_size; sector += bio_sectors(clone); crypt_inc_pending(io); @@ -1869,11 +1869,12 @@ static int crypt_map(struct dm_target *ti, struct bio *bio) if (unlikely(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))) { bio->bi_bdev = cc->dev->bdev; if (bio_sectors(bio)) - bio->bi_sector = cc->start + dm_target_offset(ti, bio->bi_sector); + bio->bi_iter.bi_sector = cc->start + + dm_target_offset(ti, bio->bi_iter.bi_sector); return DM_MAPIO_REMAPPED; } - io = crypt_io_alloc(cc, bio, dm_target_offset(ti, bio->bi_sector)); + io = crypt_io_alloc(cc, bio, dm_target_offset(ti, bio->bi_iter.bi_sector)); if (bio_data_dir(io->base_bio) == READ) { if (kcryptd_io_read(io, GFP_NOWAIT)) diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c index 496d5f3646a5..84c860191a2e 100644 --- a/drivers/md/dm-delay.c +++ b/drivers/md/dm-delay.c @@ -281,14 +281,15 @@ static int delay_map(struct dm_target *ti, struct bio *bio) if ((bio_data_dir(bio) == WRITE) && (dc->dev_write)) { bio->bi_bdev = dc->dev_write->bdev; if (bio_sectors(bio)) - bio->bi_sector = dc->start_write + - dm_target_offset(ti, bio->bi_sector); + bio->bi_iter.bi_sector = dc->start_write + + dm_target_offset(ti, bio->bi_iter.bi_sector); return delay_bio(dc, dc->write_delay, bio); } bio->bi_bdev = dc->dev_read->bdev; - bio->bi_sector = dc->start_read + dm_target_offset(ti, bio->bi_sector); + bio->bi_iter.bi_sector = dc->start_read + + dm_target_offset(ti, bio->bi_iter.bi_sector); return delay_bio(dc, dc->read_delay, bio); } diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index c80a0ec5f126..b257e46876d3 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -248,7 +248,8 @@ static void flakey_map_bio(struct dm_target *ti, struct bio *bio) bio->bi_bdev = fc->dev->bdev; if (bio_sectors(bio)) - bio->bi_sector = flakey_map_sector(ti, bio->bi_sector); + bio->bi_iter.bi_sector = + flakey_map_sector(ti, bio->bi_iter.bi_sector); } static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc) @@ -265,8 +266,8 @@ static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc) DMDEBUG("Corrupting data bio=%p by writing %u to byte %u " "(rw=%c bi_rw=%lu bi_sector=%llu cur_bytes=%u)\n", bio, fc->corrupt_bio_value, fc->corrupt_bio_byte, - (bio_data_dir(bio) == WRITE) ? 'w' : 'r', - bio->bi_rw, (unsigned long long)bio->bi_sector, bio_bytes); + (bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_rw, + (unsigned long long)bio->bi_iter.bi_sector, bio_bytes); } } diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 2a20986a2fec..01558b093307 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -304,14 +304,14 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, dm_sector_div_up(remaining, (PAGE_SIZE >> SECTOR_SHIFT))); bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios); - bio->bi_sector = where->sector + (where->count - remaining); + bio->bi_iter.bi_sector = where->sector + (where->count - remaining); bio->bi_bdev = where->bdev; bio->bi_end_io = endio; store_io_and_region_in_bio(bio, io, region); if (rw & REQ_DISCARD) { num_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining); - bio->bi_size = num_sectors << SECTOR_SHIFT; + bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT; remaining -= num_sectors; } else if (rw & REQ_WRITE_SAME) { /* @@ -320,7 +320,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where, dp->get_page(dp, &page, &len, &offset); bio_add_page(bio, page, logical_block_size, offset); num_sectors = min_t(sector_t, q->limits.max_write_same_sectors, remaining); - bio->bi_size = num_sectors << SECTOR_SHIFT; + bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT; offset = 0; remaining -= num_sectors; diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 4f99d267340c..53e848c10939 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -85,7 +85,8 @@ static void linear_map_bio(struct dm_target *ti, struct bio *bio) bio->bi_bdev = lc->dev->bdev; if (bio_sectors(bio)) - bio->bi_sector = linear_map_sector(ti, bio->bi_sector); + bio->bi_iter.bi_sector = + linear_map_sector(ti, bio->bi_iter.bi_sector); } static int linear_map(struct dm_target *ti, struct bio *bio) diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 9584443c5614..9f6d8e6baa7d 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -432,7 +432,7 @@ static int mirror_available(struct mirror_set *ms, struct bio *bio) region_t region = dm_rh_bio_to_region(ms->rh, bio); if (log->type->in_sync(log, region, 0)) - return choose_mirror(ms, bio->bi_sector) ? 1 : 0; + return choose_mirror(ms, bio->bi_iter.bi_sector) ? 1 : 0; return 0; } @@ -442,15 +442,15 @@ static int mirror_available(struct mirror_set *ms, struct bio *bio) */ static sector_t map_sector(struct mirror *m, struct bio *bio) { - if (unlikely(!bio->bi_size)) + if (unlikely(!bio->bi_iter.bi_size)) return 0; - return m->offset + dm_target_offset(m->ms->ti, bio->bi_sector); + return m->offset + dm_target_offset(m->ms->ti, bio->bi_iter.bi_sector); } static void map_bio(struct mirror *m, struct bio *bio) { bio->bi_bdev = m->dev->bdev; - bio->bi_sector = map_sector(m, bio); + bio->bi_iter.bi_sector = map_sector(m, bio); } static void map_region(struct dm_io_region *io, struct mirror *m, @@ -527,7 +527,7 @@ static void read_async_bio(struct mirror *m, struct bio *bio) struct dm_io_request io_req = { .bi_rw = READ, .mem.type = DM_IO_BVEC, - .mem.ptr.bvec = bio->bi_io_vec + bio->bi_idx, + .mem.ptr.bvec = bio->bi_io_vec + bio->bi_iter.bi_idx, .notify.fn = read_callback, .notify.context = bio, .client = m->ms->io_client, @@ -559,7 +559,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads) * We can only read balance if the region is in sync. */ if (likely(region_in_sync(ms, region, 1))) - m = choose_mirror(ms, bio->bi_sector); + m = choose_mirror(ms, bio->bi_iter.bi_sector); else if (m && atomic_read(&m->error_count)) m = NULL; @@ -630,7 +630,7 @@ static void do_write(struct mirror_set *ms, struct bio *bio) struct dm_io_request io_req = { .bi_rw = WRITE | (bio->bi_rw & WRITE_FLUSH_FUA), .mem.type = DM_IO_BVEC, - .mem.ptr.bvec = bio->bi_io_vec + bio->bi_idx, + .mem.ptr.bvec = bio->bi_io_vec + bio->bi_iter.bi_idx, .notify.fn = write_callback, .notify.context = bio, .client = ms->io_client, @@ -1181,7 +1181,7 @@ static int mirror_map(struct dm_target *ti, struct bio *bio) * The region is in-sync and we can perform reads directly. * Store enough information so we can retry if it fails. */ - m = choose_mirror(ms, bio->bi_sector); + m = choose_mirror(ms, bio->bi_iter.bi_sector); if (unlikely(!m)) return -EIO; diff --git a/drivers/md/dm-region-hash.c b/drivers/md/dm-region-hash.c index 69732e03eb34..b929fd5f4984 100644 --- a/drivers/md/dm-region-hash.c +++ b/drivers/md/dm-region-hash.c @@ -126,7 +126,8 @@ EXPORT_SYMBOL_GPL(dm_rh_region_to_sector); region_t dm_rh_bio_to_region(struct dm_region_hash *rh, struct bio *bio) { - return dm_rh_sector_to_region(rh, bio->bi_sector - rh->target_begin); + return dm_rh_sector_to_region(rh, bio->bi_iter.bi_sector - + rh->target_begin); } EXPORT_SYMBOL_GPL(dm_rh_bio_to_region); diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index aec57d76db5d..3ded8c729dfb 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -1562,11 +1562,10 @@ static void remap_exception(struct dm_snapshot *s, struct dm_exception *e, struct bio *bio, chunk_t chunk) { bio->bi_bdev = s->cow->bdev; - bio->bi_sector = chunk_to_sector(s->store, - dm_chunk_number(e->new_chunk) + - (chunk - e->old_chunk)) + - (bio->bi_sector & - s->store->chunk_mask); + bio->bi_iter.bi_sector = + chunk_to_sector(s->store, dm_chunk_number(e->new_chunk) + + (chunk - e->old_chunk)) + + (bio->bi_iter.bi_sector & s->store->chunk_mask); } static int snapshot_map(struct dm_target *ti, struct bio *bio) @@ -1584,7 +1583,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) return DM_MAPIO_REMAPPED; } - chunk = sector_to_chunk(s->store, bio->bi_sector); + chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector); /* Full snapshots are not usable */ /* To get here the table must be live so s->active is always set. */ @@ -1645,7 +1644,8 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio) r = DM_MAPIO_SUBMITTED; if (!pe->started && - bio->bi_size == (s->store->chunk_size << SECTOR_SHIFT)) { + bio->bi_iter.bi_size == + (s->store->chunk_size << SECTOR_SHIFT)) { pe->started = 1; up_write(&s->lock); start_full_bio(pe, bio); @@ -1701,7 +1701,7 @@ static int snapshot_merge_map(struct dm_target *ti, struct bio *bio) return DM_MAPIO_REMAPPED; } - chunk = sector_to_chunk(s->store, bio->bi_sector); + chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector); down_write(&s->lock); @@ -2038,7 +2038,7 @@ static int do_origin(struct dm_dev *origin, struct bio *bio) down_read(&_origins_lock); o = __lookup_origin(origin->bdev); if (o) - r = __origin_write(&o->snapshots, bio->bi_sector, bio); + r = __origin_write(&o->snapshots, bio->bi_iter.bi_sector, bio); up_read(&_origins_lock); return r; diff --git a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c index 73c1712dad96..d1600d2aa2e2 100644 --- a/drivers/md/dm-stripe.c +++ b/drivers/md/dm-stripe.c @@ -259,13 +259,15 @@ static int stripe_map_range(struct stripe_c *sc, struct bio *bio, { sector_t begin, end; - stripe_map_range_sector(sc, bio->bi_sector, target_stripe, &begin); + stripe_map_range_sector(sc, bio->bi_iter.bi_sector, + target_stripe, &begin); stripe_map_range_sector(sc, bio_end_sector(bio), target_stripe, &end); if (begin < end) { bio->bi_bdev = sc->stripe[target_stripe].dev->bdev; - bio->bi_sector = begin + sc->stripe[target_stripe].physical_start; - bio->bi_size = to_bytes(end - begin); + bio->bi_iter.bi_sector = begin + + sc->stripe[target_stripe].physical_start; + bio->bi_iter.bi_size = to_bytes(end - begin); return DM_MAPIO_REMAPPED; } else { /* The range doesn't map to the target stripe */ @@ -293,9 +295,10 @@ static int stripe_map(struct dm_target *ti, struct bio *bio) return stripe_map_range(sc, bio, target_bio_nr); } - stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector); + stripe_map_sector(sc, bio->bi_iter.bi_sector, + &stripe, &bio->bi_iter.bi_sector); - bio->bi_sector += sc->stripe[stripe].physical_start; + bio->bi_iter.bi_sector += sc->stripe[stripe].physical_start; bio->bi_bdev = sc->stripe[stripe].dev->bdev; return DM_MAPIO_REMAPPED; diff --git a/drivers/md/dm-switch.c b/drivers/md/dm-switch.c index ff9ac4be4721..09a688b3d48c 100644 --- a/drivers/md/dm-switch.c +++ b/drivers/md/dm-switch.c @@ -311,11 +311,11 @@ error: static int switch_map(struct dm_target *ti, struct bio *bio) { struct switch_ctx *sctx = ti->private; - sector_t offset = dm_target_offset(ti, bio->bi_sector); + sector_t offset = dm_target_offset(ti, bio->bi_iter.bi_sector); unsigned path_nr = switch_get_path_nr(sctx, offset); bio->bi_bdev = sctx->path_list[path_nr].dmdev->bdev; - bio->bi_sector = sctx->path_list[path_nr].start + offset; + bio->bi_iter.bi_sector = sctx->path_list[path_nr].start + offset; return DM_MAPIO_REMAPPED; } diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 2c0cf511ec23..a65402480c8c 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -413,7 +413,7 @@ static bool block_size_is_power_of_two(struct pool *pool) static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio) { struct pool *pool = tc->pool; - sector_t block_nr = bio->bi_sector; + sector_t block_nr = bio->bi_iter.bi_sector; if (block_size_is_power_of_two(pool)) block_nr >>= pool->sectors_per_block_shift; @@ -426,14 +426,15 @@ static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio) static void remap(struct thin_c *tc, struct bio *bio, dm_block_t block) { struct pool *pool = tc->pool; - sector_t bi_sector = bio->bi_sector; + sector_t bi_sector = bio->bi_iter.bi_sector; bio->bi_bdev = tc->pool_dev->bdev; if (block_size_is_power_of_two(pool)) - bio->bi_sector = (block << pool->sectors_per_block_shift) | - (bi_sector & (pool->sectors_per_block - 1)); + bio->bi_iter.bi_sector = + (block << pool->sectors_per_block_shift) | + (bi_sector & (pool->sectors_per_block - 1)); else - bio->bi_sector = (block * pool->sectors_per_block) + + bio->bi_iter.bi_sector = (block * pool->sectors_per_block) + sector_div(bi_sector, pool->sectors_per_block); } @@ -721,7 +722,8 @@ static void process_prepared(struct pool *pool, struct list_head *head, */ static int io_overlaps_block(struct pool *pool, struct bio *bio) { - return bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT); + return bio->bi_iter.bi_size == + (pool->sectors_per_block << SECTOR_SHIFT); } static int io_overwrites_block(struct pool *pool, struct bio *bio) @@ -1130,7 +1132,7 @@ static void process_shared_bio(struct thin_c *tc, struct bio *bio, if (bio_detain(pool, &key, bio, &cell)) return; - if (bio_data_dir(bio) == WRITE && bio->bi_size) + if (bio_data_dir(bio) == WRITE && bio->bi_iter.bi_size) break_sharing(tc, bio, block, &key, lookup_result, cell); else { struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook)); @@ -1153,7 +1155,7 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block /* * Remap empty bios (flushes) immediately, without provisioning. */ - if (!bio->bi_size) { + if (!bio->bi_iter.bi_size) { inc_all_io_entry(pool, bio); cell_defer_no_holder(tc, cell); @@ -1253,7 +1255,7 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio) r = dm_thin_find_block(tc->td, block, 1, &lookup_result); switch (r) { case 0: - if (lookup_result.shared && (rw == WRITE) && bio->bi_size) + if (lookup_result.shared && (rw == WRITE) && bio->bi_iter.bi_size) bio_io_error(bio); else { inc_all_io_entry(tc->pool, bio); @@ -2867,7 +2869,7 @@ out_unlock: static int thin_map(struct dm_target *ti, struct bio *bio) { - bio->bi_sector = dm_target_offset(ti, bio->bi_sector); + bio->bi_iter.bi_sector = dm_target_offset(ti, bio->bi_iter.bi_sector); return thin_bio_map(ti, bio); } diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index 4b7941db3aff..132b3154d466 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -493,9 +493,9 @@ static int verity_map(struct dm_target *ti, struct bio *bio) struct dm_verity_io *io; bio->bi_bdev = v->data_dev->bdev; - bio->bi_sector = verity_map_sector(v, bio->bi_sector); + bio->bi_iter.bi_sector = verity_map_sector(v, bio->bi_iter.bi_sector); - if (((unsigned)bio->bi_sector | bio_sectors(bio)) & + if (((unsigned)bio->bi_iter.bi_sector | bio_sectors(bio)) & ((1 << (v->data_dev_block_bits - SECTOR_SHIFT)) - 1)) { DMERR_LIMIT("unaligned io"); return -EIO; @@ -514,8 +514,8 @@ static int verity_map(struct dm_target *ti, struct bio *bio) io->v = v; io->orig_bi_end_io = bio->bi_end_io; io->orig_bi_private = bio->bi_private; - io->block = bio->bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT); - io->n_blocks = bio->bi_size >> v->data_dev_block_bits; + io->block = bio->bi_iter.bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT); + io->n_blocks = bio->bi_iter.bi_size >> v->data_dev_block_bits; bio->bi_end_io = verity_end_io; bio->bi_private = io; diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 0704c523a76b..ccd064ea4fe6 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -575,7 +575,7 @@ static void start_io_acct(struct dm_io *io) atomic_inc_return(&md->pending[rw])); if (unlikely(dm_stats_used(&md->stats))) - dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_sector, + dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_iter.bi_sector, bio_sectors(bio), false, 0, &io->stats_aux); } @@ -593,7 +593,7 @@ static void end_io_acct(struct dm_io *io) part_stat_unlock(); if (unlikely(dm_stats_used(&md->stats))) - dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_sector, + dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_iter.bi_sector, bio_sectors(bio), true, duration, &io->stats_aux); /* @@ -742,7 +742,7 @@ static void dec_pending(struct dm_io *io, int error) if (io_error == DM_ENDIO_REQUEUE) return; - if ((bio->bi_rw & REQ_FLUSH) && bio->bi_size) { + if ((bio->bi_rw & REQ_FLUSH) && bio->bi_iter.bi_size) { /* * Preflush done for flush with data, reissue * without REQ_FLUSH. @@ -797,7 +797,7 @@ static void end_clone_bio(struct bio *clone, int error) struct dm_rq_clone_bio_info *info = clone->bi_private; struct dm_rq_target_io *tio = info->tio; struct bio *bio = info->orig; - unsigned int nr_bytes = info->orig->bi_size; + unsigned int nr_bytes = info->orig->bi_iter.bi_size; bio_put(clone); @@ -1128,7 +1128,7 @@ static void __map_bio(struct dm_target_io *tio) * this io. */ atomic_inc(&tio->io->io_count); - sector = clone->bi_sector; + sector = clone->bi_iter.bi_sector; r = ti->type->map(ti, clone); if (r == DM_MAPIO_REMAPPED) { /* the bio has been remapped so dispatch it */ @@ -1160,13 +1160,13 @@ struct clone_info { static void bio_setup_sector(struct bio *bio, sector_t sector, sector_t len) { - bio->bi_sector = sector; - bio->bi_size = to_bytes(len); + bio->bi_iter.bi_sector = sector; + bio->bi_iter.bi_size = to_bytes(len); } static void bio_setup_bv(struct bio *bio, unsigned short idx, unsigned short bv_count) { - bio->bi_idx = idx; + bio->bi_iter.bi_idx = idx; bio->bi_vcnt = idx + bv_count; bio->bi_flags &= ~(1 << BIO_SEG_VALID); } @@ -1202,7 +1202,7 @@ static void clone_split_bio(struct dm_target_io *tio, struct bio *bio, clone->bi_rw = bio->bi_rw; clone->bi_vcnt = 1; clone->bi_io_vec->bv_offset = offset; - clone->bi_io_vec->bv_len = clone->bi_size; + clone->bi_io_vec->bv_len = clone->bi_iter.bi_size; clone->bi_flags |= 1 << BIO_CLONED; clone_bio_integrity(bio, clone, idx, len, offset, 1); @@ -1222,7 +1222,8 @@ static void clone_bio(struct dm_target_io *tio, struct bio *bio, bio_setup_sector(clone, sector, len); bio_setup_bv(clone, idx, bv_count); - if (idx != bio->bi_idx || clone->bi_size < bio->bi_size) + if (idx != bio->bi_iter.bi_idx || + clone->bi_iter.bi_size < bio->bi_iter.bi_size) trim = 1; clone_bio_integrity(bio, clone, idx, len, 0, trim); } @@ -1510,8 +1511,8 @@ static void __split_and_process_bio(struct mapped_device *md, ci.io->bio = bio; ci.io->md = md; spin_lock_init(&ci.io->endio_lock); - ci.sector = bio->bi_sector; - ci.idx = bio->bi_idx; + ci.sector = bio->bi_iter.bi_sector; + ci.idx = bio->bi_iter.bi_idx; start_io_acct(ci.io); diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index 3193aefe982b..e8b4574956c7 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -74,8 +74,8 @@ static void faulty_fail(struct bio *bio, int error) { struct bio *b = bio->bi_private; - b->bi_size = bio->bi_size; - b->bi_sector = bio->bi_sector; + b->bi_iter.bi_size = bio->bi_iter.bi_size; + b->bi_iter.bi_sector = bio->bi_iter.bi_sector; bio_put(bio); @@ -185,26 +185,31 @@ static void make_request(struct mddev *mddev, struct bio *bio) return; } - if (check_sector(conf, bio->bi_sector, bio_end_sector(bio), WRITE)) + if (check_sector(conf, bio->bi_iter.bi_sector, + bio_end_sector(bio), WRITE)) failit = 1; if (check_mode(conf, WritePersistent)) { - add_sector(conf, bio->bi_sector, WritePersistent); + add_sector(conf, bio->bi_iter.bi_sector, + WritePersistent); failit = 1; } if (check_mode(conf, WriteTransient)) failit = 1; } else { /* read request */ - if (check_sector(conf, bio->bi_sector, bio_end_sector(bio), READ)) + if (check_sector(conf, bio->bi_iter.bi_sector, + bio_end_sector(bio), READ)) failit = 1; if (check_mode(conf, ReadTransient)) failit = 1; if (check_mode(conf, ReadPersistent)) { - add_sector(conf, bio->bi_sector, ReadPersistent); + add_sector(conf, bio->bi_iter.bi_sector, + ReadPersistent); failit = 1; } if (check_mode(conf, ReadFixable)) { - add_sector(conf, bio->bi_sector, ReadFixable); + add_sector(conf, bio->bi_iter.bi_sector, + ReadFixable); failit = 1; } } diff --git a/drivers/md/linear.c b/drivers/md/linear.c index f03fabd2b37b..fb3b0d04edfb 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -297,19 +297,19 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio) } rcu_read_lock(); - tmp_dev = which_dev(mddev, bio->bi_sector); + tmp_dev = which_dev(mddev, bio->bi_iter.bi_sector); start_sector = tmp_dev->end_sector - tmp_dev->rdev->sectors; - if (unlikely(bio->bi_sector >= (tmp_dev->end_sector) - || (bio->bi_sector < start_sector))) { + if (unlikely(bio->bi_iter.bi_sector >= (tmp_dev->end_sector) + || (bio->bi_iter.bi_sector < start_sector))) { char b[BDEVNAME_SIZE]; printk(KERN_ERR "md/linear:%s: make_request: Sector %llu out of bounds on " "dev %s: %llu sectors, offset %llu\n", mdname(mddev), - (unsigned long long)bio->bi_sector, + (unsigned long long)bio->bi_iter.bi_sector, bdevname(tmp_dev->rdev->bdev, b), (unsigned long long)tmp_dev->rdev->sectors, (unsigned long long)start_sector); @@ -326,7 +326,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio) rcu_read_unlock(); - bp = bio_split(bio, end_sector - bio->bi_sector); + bp = bio_split(bio, end_sector - bio->bi_iter.bi_sector); linear_make_request(mddev, &bp->bio1); linear_make_request(mddev, &bp->bio2); @@ -335,7 +335,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio) } bio->bi_bdev = tmp_dev->rdev->bdev; - bio->bi_sector = bio->bi_sector - start_sector + bio->bi_iter.bi_sector = bio->bi_iter.bi_sector - start_sector + tmp_dev->rdev->data_offset; rcu_read_unlock(); diff --git a/drivers/md/md.c b/drivers/md/md.c index 739b1ec54e28..b07fed398fd7 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -393,7 +393,7 @@ static void md_submit_flush_data(struct work_struct *ws) struct mddev *mddev = container_of(ws, struct mddev, flush_work); struct bio *bio = mddev->flush_bio; - if (bio->bi_size == 0) + if (bio->bi_iter.bi_size == 0) /* an empty barrier - all done */ bio_endio(bio, 0); else { @@ -754,7 +754,7 @@ void md_super_write(struct mddev *mddev, struct md_rdev *rdev, struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, mddev); bio->bi_bdev = rdev->meta_bdev ? rdev->meta_bdev : rdev->bdev; - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio_add_page(bio, page, size, 0); bio->bi_private = rdev; bio->bi_end_io = super_written; @@ -785,13 +785,13 @@ int sync_page_io(struct md_rdev *rdev, sector_t sector, int size, bio->bi_bdev = (metadata_op && rdev->meta_bdev) ? rdev->meta_bdev : rdev->bdev; if (metadata_op) - bio->bi_sector = sector + rdev->sb_start; + bio->bi_iter.bi_sector = sector + rdev->sb_start; else if (rdev->mddev->reshape_position != MaxSector && (rdev->mddev->reshape_backwards == (sector >= rdev->mddev->reshape_position))) - bio->bi_sector = sector + rdev->new_data_offset; + bio->bi_iter.bi_sector = sector + rdev->new_data_offset; else - bio->bi_sector = sector + rdev->data_offset; + bio->bi_iter.bi_sector = sector + rdev->data_offset; bio_add_page(bio, page, size, 0); submit_bio_wait(rw, bio); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 1642eae75a33..849ad39f547b 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -100,7 +100,7 @@ static void multipath_end_request(struct bio *bio, int error) md_error (mp_bh->mddev, rdev); printk(KERN_ERR "multipath: %s: rescheduling sector %llu\n", bdevname(rdev->bdev,b), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); multipath_reschedule_retry(mp_bh); } else multipath_end_bh_io(mp_bh, error); @@ -132,7 +132,7 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio) multipath = conf->multipaths + mp_bh->path; mp_bh->bio = *bio; - mp_bh->bio.bi_sector += multipath->rdev->data_offset; + mp_bh->bio.bi_iter.bi_sector += multipath->rdev->data_offset; mp_bh->bio.bi_bdev = multipath->rdev->bdev; mp_bh->bio.bi_rw |= REQ_FAILFAST_TRANSPORT; mp_bh->bio.bi_end_io = multipath_end_request; @@ -355,21 +355,22 @@ static void multipathd(struct md_thread *thread) spin_unlock_irqrestore(&conf->device_lock, flags); bio = &mp_bh->bio; - bio->bi_sector = mp_bh->master_bio->bi_sector; + bio->bi_iter.bi_sector = mp_bh->master_bio->bi_iter.bi_sector; if ((mp_bh->path = multipath_map (conf))<0) { printk(KERN_ALERT "multipath: %s: unrecoverable IO read" " error for block %llu\n", bdevname(bio->bi_bdev,b), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); multipath_end_bh_io(mp_bh, -EIO); } else { printk(KERN_ERR "multipath: %s: redirecting sector %llu" " to another IO path\n", bdevname(bio->bi_bdev,b), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); *bio = *(mp_bh->master_bio); - bio->bi_sector += conf->multipaths[mp_bh->path].rdev->data_offset; + bio->bi_iter.bi_sector += + conf->multipaths[mp_bh->path].rdev->data_offset; bio->bi_bdev = conf->multipaths[mp_bh->path].rdev->bdev; bio->bi_rw |= REQ_FAILFAST_TRANSPORT; bio->bi_end_io = multipath_end_request; diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index c4d420b7d2f4..e38d1d3226f3 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -501,10 +501,11 @@ static inline int is_io_in_chunk_boundary(struct mddev *mddev, unsigned int chunk_sects, struct bio *bio) { if (likely(is_power_of_2(chunk_sects))) { - return chunk_sects >= ((bio->bi_sector & (chunk_sects-1)) + return chunk_sects >= + ((bio->bi_iter.bi_sector & (chunk_sects-1)) + bio_sectors(bio)); } else{ - sector_t sector = bio->bi_sector; + sector_t sector = bio->bi_iter.bi_sector; return chunk_sects >= (sector_div(sector, chunk_sects) + bio_sectors(bio)); } @@ -524,7 +525,7 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio) chunk_sects = mddev->chunk_sectors; if (unlikely(!is_io_in_chunk_boundary(mddev, chunk_sects, bio))) { - sector_t sector = bio->bi_sector; + sector_t sector = bio->bi_iter.bi_sector; struct bio_pair *bp; /* Sanity check -- queue functions should prevent this happening */ if (bio_segments(bio) > 1) @@ -544,12 +545,12 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio) return; } - sector_offset = bio->bi_sector; + sector_offset = bio->bi_iter.bi_sector; zone = find_zone(mddev->private, §or_offset); - tmp_dev = map_sector(mddev, zone, bio->bi_sector, + tmp_dev = map_sector(mddev, zone, bio->bi_iter.bi_sector, §or_offset); bio->bi_bdev = tmp_dev->bdev; - bio->bi_sector = sector_offset + zone->dev_start + + bio->bi_iter.bi_sector = sector_offset + zone->dev_start + tmp_dev->data_offset; if (unlikely((bio->bi_rw & REQ_DISCARD) && @@ -566,7 +567,8 @@ bad_map: printk("md/raid0:%s: make_request bug: can't convert block across chunks" " or bigger than %dk %llu %d\n", mdname(mddev), chunk_sects / 2, - (unsigned long long)bio->bi_sector, bio_sectors(bio) / 2); + (unsigned long long)bio->bi_iter.bi_sector, + bio_sectors(bio) / 2); bio_io_error(bio); return; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 1e5a540995e9..db3b9d7314f1 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -229,7 +229,7 @@ static void call_bio_endio(struct r1bio *r1_bio) int done; struct r1conf *conf = r1_bio->mddev->private; sector_t start_next_window = r1_bio->start_next_window; - sector_t bi_sector = bio->bi_sector; + sector_t bi_sector = bio->bi_iter.bi_sector; if (bio->bi_phys_segments) { unsigned long flags; @@ -265,9 +265,8 @@ static void raid_end_bio_io(struct r1bio *r1_bio) if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) { pr_debug("raid1: sync end %s on sectors %llu-%llu\n", (bio_data_dir(bio) == WRITE) ? "write" : "read", - (unsigned long long) bio->bi_sector, - (unsigned long long) bio->bi_sector + - bio_sectors(bio) - 1); + (unsigned long long) bio->bi_iter.bi_sector, + (unsigned long long) bio_end_sector(bio) - 1); call_bio_endio(r1_bio); } @@ -466,9 +465,8 @@ static void raid1_end_write_request(struct bio *bio, int error) struct bio *mbio = r1_bio->master_bio; pr_debug("raid1: behind end write sectors" " %llu-%llu\n", - (unsigned long long) mbio->bi_sector, - (unsigned long long) mbio->bi_sector + - bio_sectors(mbio) - 1); + (unsigned long long) mbio->bi_iter.bi_sector, + (unsigned long long) bio_end_sector(mbio) - 1); call_bio_endio(r1_bio); } } @@ -875,7 +873,7 @@ static bool need_to_wait_for_sync(struct r1conf *conf, struct bio *bio) else if ((conf->next_resync - RESYNC_WINDOW_SECTORS >= bio_end_sector(bio)) || (conf->next_resync + NEXT_NORMALIO_DISTANCE - <= bio->bi_sector)) + <= bio->bi_iter.bi_sector)) wait = false; else wait = true; @@ -913,19 +911,19 @@ static sector_t wait_barrier(struct r1conf *conf, struct bio *bio) if (bio && bio_data_dir(bio) == WRITE) { if (conf->next_resync + NEXT_NORMALIO_DISTANCE - <= bio->bi_sector) { + <= bio->bi_iter.bi_sector) { if (conf->start_next_window == MaxSector) conf->start_next_window = conf->next_resync + NEXT_NORMALIO_DISTANCE; if ((conf->start_next_window + NEXT_NORMALIO_DISTANCE) - <= bio->bi_sector) + <= bio->bi_iter.bi_sector) conf->next_window_requests++; else conf->current_window_requests++; } - if (bio->bi_sector >= conf->start_next_window) + if (bio->bi_iter.bi_sector >= conf->start_next_window) sector = conf->start_next_window; } @@ -1028,7 +1026,8 @@ do_sync_io: if (bvecs[i].bv_page) put_page(bvecs[i].bv_page); kfree(bvecs); - pr_debug("%dB behind alloc failed, doing sync I/O\n", bio->bi_size); + pr_debug("%dB behind alloc failed, doing sync I/O\n", + bio->bi_iter.bi_size); } struct raid1_plug_cb { @@ -1108,7 +1107,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) if (bio_data_dir(bio) == WRITE && bio_end_sector(bio) > mddev->suspend_lo && - bio->bi_sector < mddev->suspend_hi) { + bio->bi_iter.bi_sector < mddev->suspend_hi) { /* As the suspend_* range is controlled by * userspace, we want an interruptible * wait. @@ -1119,7 +1118,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) prepare_to_wait(&conf->wait_barrier, &w, TASK_INTERRUPTIBLE); if (bio_end_sector(bio) <= mddev->suspend_lo || - bio->bi_sector >= mddev->suspend_hi) + bio->bi_iter.bi_sector >= mddev->suspend_hi) break; schedule(); } @@ -1141,7 +1140,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) r1_bio->sectors = bio_sectors(bio); r1_bio->state = 0; r1_bio->mddev = mddev; - r1_bio->sector = bio->bi_sector; + r1_bio->sector = bio->bi_iter.bi_sector; /* We might need to issue multiple reads to different * devices if there are bad blocks around, so we keep @@ -1181,12 +1180,13 @@ read_again: r1_bio->read_disk = rdisk; read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(read_bio, r1_bio->sector - bio->bi_sector, + bio_trim(read_bio, r1_bio->sector - bio->bi_iter.bi_sector, max_sectors); r1_bio->bios[rdisk] = read_bio; - read_bio->bi_sector = r1_bio->sector + mirror->rdev->data_offset; + read_bio->bi_iter.bi_sector = r1_bio->sector + + mirror->rdev->data_offset; read_bio->bi_bdev = mirror->rdev->bdev; read_bio->bi_end_io = raid1_end_read_request; read_bio->bi_rw = READ | do_sync; @@ -1198,7 +1198,7 @@ read_again: */ sectors_handled = (r1_bio->sector + max_sectors - - bio->bi_sector); + - bio->bi_iter.bi_sector); r1_bio->sectors = max_sectors; spin_lock_irq(&conf->device_lock); if (bio->bi_phys_segments == 0) @@ -1219,7 +1219,8 @@ read_again: r1_bio->sectors = bio_sectors(bio) - sectors_handled; r1_bio->state = 0; r1_bio->mddev = mddev; - r1_bio->sector = bio->bi_sector + sectors_handled; + r1_bio->sector = bio->bi_iter.bi_sector + + sectors_handled; goto read_again; } else generic_make_request(read_bio); @@ -1322,7 +1323,7 @@ read_again: if (r1_bio->bios[j]) rdev_dec_pending(conf->mirrors[j].rdev, mddev); r1_bio->state = 0; - allow_barrier(conf, start_next_window, bio->bi_sector); + allow_barrier(conf, start_next_window, bio->bi_iter.bi_sector); md_wait_for_blocked_rdev(blocked_rdev, mddev); start_next_window = wait_barrier(conf, bio); /* @@ -1349,7 +1350,7 @@ read_again: bio->bi_phys_segments++; spin_unlock_irq(&conf->device_lock); } - sectors_handled = r1_bio->sector + max_sectors - bio->bi_sector; + sectors_handled = r1_bio->sector + max_sectors - bio->bi_iter.bi_sector; atomic_set(&r1_bio->remaining, 1); atomic_set(&r1_bio->behind_remaining, 0); @@ -1361,7 +1362,7 @@ read_again: continue; mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(mbio, r1_bio->sector - bio->bi_sector, max_sectors); + bio_trim(mbio, r1_bio->sector - bio->bi_iter.bi_sector, max_sectors); if (first_clone) { /* do behind I/O ? @@ -1395,7 +1396,7 @@ read_again: r1_bio->bios[i] = mbio; - mbio->bi_sector = (r1_bio->sector + + mbio->bi_iter.bi_sector = (r1_bio->sector + conf->mirrors[i].rdev->data_offset); mbio->bi_bdev = conf->mirrors[i].rdev->bdev; mbio->bi_end_io = raid1_end_write_request; @@ -1435,7 +1436,7 @@ read_again: r1_bio->sectors = bio_sectors(bio) - sectors_handled; r1_bio->state = 0; r1_bio->mddev = mddev; - r1_bio->sector = bio->bi_sector + sectors_handled; + r1_bio->sector = bio->bi_iter.bi_sector + sectors_handled; goto retry_write; } @@ -1959,14 +1960,14 @@ static int process_checks(struct r1bio *r1_bio) /* fixup the bio for reuse */ bio_reset(b); b->bi_vcnt = vcnt; - b->bi_size = r1_bio->sectors << 9; - b->bi_sector = r1_bio->sector + + b->bi_iter.bi_size = r1_bio->sectors << 9; + b->bi_iter.bi_sector = r1_bio->sector + conf->mirrors[i].rdev->data_offset; b->bi_bdev = conf->mirrors[i].rdev->bdev; b->bi_end_io = end_sync_read; b->bi_private = r1_bio; - size = b->bi_size; + size = b->bi_iter.bi_size; for (j = 0; j < vcnt ; j++) { struct bio_vec *bi; bi = &b->bi_io_vec[j]; @@ -2221,11 +2222,11 @@ static int narrow_write_error(struct r1bio *r1_bio, int i) } wbio->bi_rw = WRITE; - wbio->bi_sector = r1_bio->sector; - wbio->bi_size = r1_bio->sectors << 9; + wbio->bi_iter.bi_sector = r1_bio->sector; + wbio->bi_iter.bi_size = r1_bio->sectors << 9; bio_trim(wbio, sector - r1_bio->sector, sectors); - wbio->bi_sector += rdev->data_offset; + wbio->bi_iter.bi_sector += rdev->data_offset; wbio->bi_bdev = rdev->bdev; if (submit_bio_wait(WRITE, wbio) == 0) /* failure! */ @@ -2339,7 +2340,8 @@ read_more: } r1_bio->read_disk = disk; bio = bio_clone_mddev(r1_bio->master_bio, GFP_NOIO, mddev); - bio_trim(bio, r1_bio->sector - bio->bi_sector, max_sectors); + bio_trim(bio, r1_bio->sector - bio->bi_iter.bi_sector, + max_sectors); r1_bio->bios[r1_bio->read_disk] = bio; rdev = conf->mirrors[disk].rdev; printk_ratelimited(KERN_ERR @@ -2348,7 +2350,7 @@ read_more: mdname(mddev), (unsigned long long)r1_bio->sector, bdevname(rdev->bdev, b)); - bio->bi_sector = r1_bio->sector + rdev->data_offset; + bio->bi_iter.bi_sector = r1_bio->sector + rdev->data_offset; bio->bi_bdev = rdev->bdev; bio->bi_end_io = raid1_end_read_request; bio->bi_rw = READ | do_sync; @@ -2357,7 +2359,7 @@ read_more: /* Drat - have to split this up more */ struct bio *mbio = r1_bio->master_bio; int sectors_handled = (r1_bio->sector + max_sectors - - mbio->bi_sector); + - mbio->bi_iter.bi_sector); r1_bio->sectors = max_sectors; spin_lock_irq(&conf->device_lock); if (mbio->bi_phys_segments == 0) @@ -2375,7 +2377,8 @@ read_more: r1_bio->state = 0; set_bit(R1BIO_ReadError, &r1_bio->state); r1_bio->mddev = mddev; - r1_bio->sector = mbio->bi_sector + sectors_handled; + r1_bio->sector = mbio->bi_iter.bi_sector + + sectors_handled; goto read_more; } else @@ -2599,7 +2602,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp } if (bio->bi_end_io) { atomic_inc(&rdev->nr_pending); - bio->bi_sector = sector_nr + rdev->data_offset; + bio->bi_iter.bi_sector = sector_nr + rdev->data_offset; bio->bi_bdev = rdev->bdev; bio->bi_private = r1_bio; } @@ -2699,7 +2702,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp continue; /* remove last page from this bio */ bio->bi_vcnt--; - bio->bi_size -= len; + bio->bi_iter.bi_size -= len; bio->bi_flags &= ~(1<< BIO_SEG_VALID); } goto bio_full; diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index c504e8389e69..dbf3b63c2754 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1182,7 +1182,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) /* If this request crosses a chunk boundary, we need to * split it. This will only happen for 1 PAGE (or less) requests. */ - if (unlikely((bio->bi_sector & chunk_mask) + bio_sectors(bio) + if (unlikely((bio->bi_iter.bi_sector & chunk_mask) + bio_sectors(bio) > chunk_sects && (conf->geo.near_copies < conf->geo.raid_disks || conf->prev.near_copies < conf->prev.raid_disks))) { @@ -1193,8 +1193,8 @@ static void make_request(struct mddev *mddev, struct bio * bio) /* This is a one page bio that upper layers * refuse to split for us, so we need to split it. */ - bp = bio_split(bio, - chunk_sects - (bio->bi_sector & (chunk_sects - 1)) ); + bp = bio_split(bio, chunk_sects - + (bio->bi_iter.bi_sector & (chunk_sects - 1))); /* Each of these 'make_request' calls will call 'wait_barrier'. * If the first succeeds but the second blocks due to the resync @@ -1221,7 +1221,8 @@ static void make_request(struct mddev *mddev, struct bio * bio) bad_map: printk("md/raid10:%s: make_request bug: can't convert block across chunks" " or bigger than %dk %llu %d\n", mdname(mddev), chunk_sects/2, - (unsigned long long)bio->bi_sector, bio_sectors(bio) / 2); + (unsigned long long)bio->bi_iter.bi_sector, + bio_sectors(bio) / 2); bio_io_error(bio); return; @@ -1238,24 +1239,25 @@ static void make_request(struct mddev *mddev, struct bio * bio) sectors = bio_sectors(bio); while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && - bio->bi_sector < conf->reshape_progress && - bio->bi_sector + sectors > conf->reshape_progress) { + bio->bi_iter.bi_sector < conf->reshape_progress && + bio->bi_iter.bi_sector + sectors > conf->reshape_progress) { /* IO spans the reshape position. Need to wait for * reshape to pass */ allow_barrier(conf); wait_event(conf->wait_barrier, - conf->reshape_progress <= bio->bi_sector || - conf->reshape_progress >= bio->bi_sector + sectors); + conf->reshape_progress <= bio->bi_iter.bi_sector || + conf->reshape_progress >= bio->bi_iter.bi_sector + + sectors); wait_barrier(conf); } if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && bio_data_dir(bio) == WRITE && (mddev->reshape_backwards - ? (bio->bi_sector < conf->reshape_safe && - bio->bi_sector + sectors > conf->reshape_progress) - : (bio->bi_sector + sectors > conf->reshape_safe && - bio->bi_sector < conf->reshape_progress))) { + ? (bio->bi_iter.bi_sector < conf->reshape_safe && + bio->bi_iter.bi_sector + sectors > conf->reshape_progress) + : (bio->bi_iter.bi_sector + sectors > conf->reshape_safe && + bio->bi_iter.bi_sector < conf->reshape_progress))) { /* Need to update reshape_position in metadata */ mddev->reshape_position = conf->reshape_progress; set_bit(MD_CHANGE_DEVS, &mddev->flags); @@ -1273,7 +1275,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) r10_bio->sectors = sectors; r10_bio->mddev = mddev; - r10_bio->sector = bio->bi_sector; + r10_bio->sector = bio->bi_iter.bi_sector; r10_bio->state = 0; /* We might need to issue multiple reads to different @@ -1302,13 +1304,13 @@ read_again: slot = r10_bio->read_slot; read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(read_bio, r10_bio->sector - bio->bi_sector, + bio_trim(read_bio, r10_bio->sector - bio->bi_iter.bi_sector, max_sectors); r10_bio->devs[slot].bio = read_bio; r10_bio->devs[slot].rdev = rdev; - read_bio->bi_sector = r10_bio->devs[slot].addr + + read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr + choose_data_offset(r10_bio, rdev); read_bio->bi_bdev = rdev->bdev; read_bio->bi_end_io = raid10_end_read_request; @@ -1320,7 +1322,7 @@ read_again: * need another r10_bio. */ sectors_handled = (r10_bio->sectors + max_sectors - - bio->bi_sector); + - bio->bi_iter.bi_sector); r10_bio->sectors = max_sectors; spin_lock_irq(&conf->device_lock); if (bio->bi_phys_segments == 0) @@ -1341,7 +1343,8 @@ read_again: r10_bio->sectors = bio_sectors(bio) - sectors_handled; r10_bio->state = 0; r10_bio->mddev = mddev; - r10_bio->sector = bio->bi_sector + sectors_handled; + r10_bio->sector = bio->bi_iter.bi_sector + + sectors_handled; goto read_again; } else generic_make_request(read_bio); @@ -1499,7 +1502,8 @@ retry_write: bio->bi_phys_segments++; spin_unlock_irq(&conf->device_lock); } - sectors_handled = r10_bio->sector + max_sectors - bio->bi_sector; + sectors_handled = r10_bio->sector + max_sectors - + bio->bi_iter.bi_sector; atomic_set(&r10_bio->remaining, 1); bitmap_startwrite(mddev->bitmap, r10_bio->sector, r10_bio->sectors, 0); @@ -1510,11 +1514,11 @@ retry_write: if (r10_bio->devs[i].bio) { struct md_rdev *rdev = conf->mirrors[d].rdev; mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(mbio, r10_bio->sector - bio->bi_sector, + bio_trim(mbio, r10_bio->sector - bio->bi_iter.bi_sector, max_sectors); r10_bio->devs[i].bio = mbio; - mbio->bi_sector = (r10_bio->devs[i].addr+ + mbio->bi_iter.bi_sector = (r10_bio->devs[i].addr+ choose_data_offset(r10_bio, rdev)); mbio->bi_bdev = rdev->bdev; @@ -1553,11 +1557,11 @@ retry_write: rdev = conf->mirrors[d].rdev; } mbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(mbio, r10_bio->sector - bio->bi_sector, + bio_trim(mbio, r10_bio->sector - bio->bi_iter.bi_sector, max_sectors); r10_bio->devs[i].repl_bio = mbio; - mbio->bi_sector = (r10_bio->devs[i].addr + + mbio->bi_iter.bi_sector = (r10_bio->devs[i].addr + choose_data_offset( r10_bio, rdev)); mbio->bi_bdev = rdev->bdev; @@ -1591,7 +1595,7 @@ retry_write: r10_bio->sectors = bio_sectors(bio) - sectors_handled; r10_bio->mddev = mddev; - r10_bio->sector = bio->bi_sector + sectors_handled; + r10_bio->sector = bio->bi_iter.bi_sector + sectors_handled; r10_bio->state = 0; goto retry_write; } @@ -2124,10 +2128,10 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) bio_reset(tbio); tbio->bi_vcnt = vcnt; - tbio->bi_size = r10_bio->sectors << 9; + tbio->bi_iter.bi_size = r10_bio->sectors << 9; tbio->bi_rw = WRITE; tbio->bi_private = r10_bio; - tbio->bi_sector = r10_bio->devs[i].addr; + tbio->bi_iter.bi_sector = r10_bio->devs[i].addr; for (j=0; j < vcnt ; j++) { tbio->bi_io_vec[j].bv_offset = 0; @@ -2144,7 +2148,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio) atomic_inc(&r10_bio->remaining); md_sync_acct(conf->mirrors[d].rdev->bdev, bio_sectors(tbio)); - tbio->bi_sector += conf->mirrors[d].rdev->data_offset; + tbio->bi_iter.bi_sector += conf->mirrors[d].rdev->data_offset; tbio->bi_bdev = conf->mirrors[d].rdev->bdev; generic_make_request(tbio); } @@ -2614,8 +2618,8 @@ static int narrow_write_error(struct r10bio *r10_bio, int i) sectors = sect_to_write; /* Write at 'sector' for 'sectors' */ wbio = bio_clone_mddev(bio, GFP_NOIO, mddev); - bio_trim(wbio, sector - bio->bi_sector, sectors); - wbio->bi_sector = (r10_bio->devs[i].addr+ + bio_trim(wbio, sector - bio->bi_iter.bi_sector, sectors); + wbio->bi_iter.bi_sector = (r10_bio->devs[i].addr+ choose_data_offset(r10_bio, rdev) + (sector - r10_bio->sector)); wbio->bi_bdev = rdev->bdev; @@ -2687,10 +2691,10 @@ read_more: (unsigned long long)r10_bio->sector); bio = bio_clone_mddev(r10_bio->master_bio, GFP_NOIO, mddev); - bio_trim(bio, r10_bio->sector - bio->bi_sector, max_sectors); + bio_trim(bio, r10_bio->sector - bio->bi_iter.bi_sector, max_sectors); r10_bio->devs[slot].bio = bio; r10_bio->devs[slot].rdev = rdev; - bio->bi_sector = r10_bio->devs[slot].addr + bio->bi_iter.bi_sector = r10_bio->devs[slot].addr + choose_data_offset(r10_bio, rdev); bio->bi_bdev = rdev->bdev; bio->bi_rw = READ | do_sync; @@ -2701,7 +2705,7 @@ read_more: struct bio *mbio = r10_bio->master_bio; int sectors_handled = r10_bio->sector + max_sectors - - mbio->bi_sector; + - mbio->bi_iter.bi_sector; r10_bio->sectors = max_sectors; spin_lock_irq(&conf->device_lock); if (mbio->bi_phys_segments == 0) @@ -2719,7 +2723,7 @@ read_more: set_bit(R10BIO_ReadError, &r10_bio->state); r10_bio->mddev = mddev; - r10_bio->sector = mbio->bi_sector + r10_bio->sector = mbio->bi_iter.bi_sector + sectors_handled; goto read_more; @@ -3157,7 +3161,8 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio->bi_end_io = end_sync_read; bio->bi_rw = READ; from_addr = r10_bio->devs[j].addr; - bio->bi_sector = from_addr + rdev->data_offset; + bio->bi_iter.bi_sector = from_addr + + rdev->data_offset; bio->bi_bdev = rdev->bdev; atomic_inc(&rdev->nr_pending); /* and we write to 'i' (if not in_sync) */ @@ -3181,7 +3186,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio->bi_private = r10_bio; bio->bi_end_io = end_sync_write; bio->bi_rw = WRITE; - bio->bi_sector = to_addr + bio->bi_iter.bi_sector = to_addr + rdev->data_offset; bio->bi_bdev = rdev->bdev; atomic_inc(&r10_bio->remaining); @@ -3210,7 +3215,8 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio->bi_private = r10_bio; bio->bi_end_io = end_sync_write; bio->bi_rw = WRITE; - bio->bi_sector = to_addr + rdev->data_offset; + bio->bi_iter.bi_sector = to_addr + + rdev->data_offset; bio->bi_bdev = rdev->bdev; atomic_inc(&r10_bio->remaining); break; @@ -3328,7 +3334,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio->bi_private = r10_bio; bio->bi_end_io = end_sync_read; bio->bi_rw = READ; - bio->bi_sector = sector + + bio->bi_iter.bi_sector = sector + conf->mirrors[d].rdev->data_offset; bio->bi_bdev = conf->mirrors[d].rdev->bdev; count++; @@ -3350,7 +3356,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio->bi_private = r10_bio; bio->bi_end_io = end_sync_write; bio->bi_rw = WRITE; - bio->bi_sector = sector + + bio->bi_iter.bi_sector = sector + conf->mirrors[d].replacement->data_offset; bio->bi_bdev = conf->mirrors[d].replacement->bdev; count++; @@ -3397,7 +3403,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, bio2 = bio2->bi_next) { /* remove last page from this bio */ bio2->bi_vcnt--; - bio2->bi_size -= len; + bio2->bi_iter.bi_size -= len; bio2->bi_flags &= ~(1<< BIO_SEG_VALID); } goto bio_full; @@ -4417,7 +4423,7 @@ read_more: read_bio = bio_alloc_mddev(GFP_KERNEL, RESYNC_PAGES, mddev); read_bio->bi_bdev = rdev->bdev; - read_bio->bi_sector = (r10_bio->devs[r10_bio->read_slot].addr + read_bio->bi_iter.bi_sector = (r10_bio->devs[r10_bio->read_slot].addr + rdev->data_offset); read_bio->bi_private = r10_bio; read_bio->bi_end_io = end_sync_read; @@ -4425,7 +4431,7 @@ read_more: read_bio->bi_flags &= ~(BIO_POOL_MASK - 1); read_bio->bi_flags |= 1 << BIO_UPTODATE; read_bio->bi_vcnt = 0; - read_bio->bi_size = 0; + read_bio->bi_iter.bi_size = 0; r10_bio->master_bio = read_bio; r10_bio->read_slot = r10_bio->devs[r10_bio->read_slot].devnum; @@ -4451,7 +4457,8 @@ read_more: bio_reset(b); b->bi_bdev = rdev2->bdev; - b->bi_sector = r10_bio->devs[s/2].addr + rdev2->new_data_offset; + b->bi_iter.bi_sector = r10_bio->devs[s/2].addr + + rdev2->new_data_offset; b->bi_private = r10_bio; b->bi_end_io = end_reshape_write; b->bi_rw = WRITE; @@ -4478,7 +4485,7 @@ read_more: bio2 = bio2->bi_next) { /* Remove last page from this bio */ bio2->bi_vcnt--; - bio2->bi_size -= len; + bio2->bi_iter.bi_size -= len; bio2->bi_flags &= ~(1<bi_sector + sectors < sector + STRIPE_SECTORS) + if (bio->bi_iter.bi_sector + sectors < sector + STRIPE_SECTORS) return bio->bi_next; else return NULL; @@ -225,7 +225,7 @@ static void return_io(struct bio *return_bi) return_bi = bi->bi_next; bi->bi_next = NULL; - bi->bi_size = 0; + bi->bi_iter.bi_size = 0; trace_block_bio_complete(bdev_get_queue(bi->bi_bdev), bi, 0); bio_endio(bi, 0); @@ -854,10 +854,10 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) bi->bi_rw, i); atomic_inc(&sh->count); if (use_new_offset(conf, sh)) - bi->bi_sector = (sh->sector + bi->bi_iter.bi_sector = (sh->sector + rdev->new_data_offset); else - bi->bi_sector = (sh->sector + bi->bi_iter.bi_sector = (sh->sector + rdev->data_offset); if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags)) bi->bi_rw |= REQ_NOMERGE; @@ -865,7 +865,7 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) bi->bi_vcnt = 1; bi->bi_io_vec[0].bv_len = STRIPE_SIZE; bi->bi_io_vec[0].bv_offset = 0; - bi->bi_size = STRIPE_SIZE; + bi->bi_iter.bi_size = STRIPE_SIZE; /* * If this is discard request, set bi_vcnt 0. We don't * want to confuse SCSI because SCSI will replace payload @@ -901,15 +901,15 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s) rbi->bi_rw, i); atomic_inc(&sh->count); if (use_new_offset(conf, sh)) - rbi->bi_sector = (sh->sector + rbi->bi_iter.bi_sector = (sh->sector + rrdev->new_data_offset); else - rbi->bi_sector = (sh->sector + rbi->bi_iter.bi_sector = (sh->sector + rrdev->data_offset); rbi->bi_vcnt = 1; rbi->bi_io_vec[0].bv_len = STRIPE_SIZE; rbi->bi_io_vec[0].bv_offset = 0; - rbi->bi_size = STRIPE_SIZE; + rbi->bi_iter.bi_size = STRIPE_SIZE; /* * If this is discard request, set bi_vcnt 0. We don't * want to confuse SCSI because SCSI will replace payload @@ -944,10 +944,10 @@ async_copy_data(int frombio, struct bio *bio, struct page *page, struct async_submit_ctl submit; enum async_tx_flags flags = 0; - if (bio->bi_sector >= sector) - page_offset = (signed)(bio->bi_sector - sector) * 512; + if (bio->bi_iter.bi_sector >= sector) + page_offset = (signed)(bio->bi_iter.bi_sector - sector) * 512; else - page_offset = (signed)(sector - bio->bi_sector) * -512; + page_offset = (signed)(sector - bio->bi_iter.bi_sector) * -512; if (frombio) flags |= ASYNC_TX_FENCE; @@ -1014,7 +1014,7 @@ static void ops_complete_biofill(void *stripe_head_ref) BUG_ON(!dev->read); rbi = dev->read; dev->read = NULL; - while (rbi && rbi->bi_sector < + while (rbi && rbi->bi_iter.bi_sector < dev->sector + STRIPE_SECTORS) { rbi2 = r5_next_bio(rbi, dev->sector); if (!raid5_dec_bi_active_stripes(rbi)) { @@ -1050,7 +1050,7 @@ static void ops_run_biofill(struct stripe_head *sh) dev->read = rbi = dev->toread; dev->toread = NULL; spin_unlock_irq(&sh->stripe_lock); - while (rbi && rbi->bi_sector < + while (rbi && rbi->bi_iter.bi_sector < dev->sector + STRIPE_SECTORS) { tx = async_copy_data(0, rbi, dev->page, dev->sector, tx); @@ -1392,7 +1392,7 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx) wbi = dev->written = chosen; spin_unlock_irq(&sh->stripe_lock); - while (wbi && wbi->bi_sector < + while (wbi && wbi->bi_iter.bi_sector < dev->sector + STRIPE_SECTORS) { if (wbi->bi_rw & REQ_FUA) set_bit(R5_WantFUA, &dev->flags); @@ -2616,7 +2616,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in int firstwrite=0; pr_debug("adding bi b#%llu to stripe s#%llu\n", - (unsigned long long)bi->bi_sector, + (unsigned long long)bi->bi_iter.bi_sector, (unsigned long long)sh->sector); /* @@ -2634,12 +2634,12 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in firstwrite = 1; } else bip = &sh->dev[dd_idx].toread; - while (*bip && (*bip)->bi_sector < bi->bi_sector) { - if (bio_end_sector(*bip) > bi->bi_sector) + while (*bip && (*bip)->bi_iter.bi_sector < bi->bi_iter.bi_sector) { + if (bio_end_sector(*bip) > bi->bi_iter.bi_sector) goto overlap; bip = & (*bip)->bi_next; } - if (*bip && (*bip)->bi_sector < bio_end_sector(bi)) + if (*bip && (*bip)->bi_iter.bi_sector < bio_end_sector(bi)) goto overlap; BUG_ON(*bip && bi->bi_next && (*bip) != bi->bi_next); @@ -2653,7 +2653,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in sector_t sector = sh->dev[dd_idx].sector; for (bi=sh->dev[dd_idx].towrite; sector < sh->dev[dd_idx].sector + STRIPE_SECTORS && - bi && bi->bi_sector <= sector; + bi && bi->bi_iter.bi_sector <= sector; bi = r5_next_bio(bi, sh->dev[dd_idx].sector)) { if (bio_end_sector(bi) >= sector) sector = bio_end_sector(bi); @@ -2663,7 +2663,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in } pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n", - (unsigned long long)(*bip)->bi_sector, + (unsigned long long)(*bip)->bi_iter.bi_sector, (unsigned long long)sh->sector, dd_idx); spin_unlock_irq(&sh->stripe_lock); @@ -2738,7 +2738,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) wake_up(&conf->wait_for_overlap); - while (bi && bi->bi_sector < + while (bi && bi->bi_iter.bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); clear_bit(BIO_UPTODATE, &bi->bi_flags); @@ -2757,7 +2757,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, bi = sh->dev[i].written; sh->dev[i].written = NULL; if (bi) bitmap_end = 1; - while (bi && bi->bi_sector < + while (bi && bi->bi_iter.bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector); clear_bit(BIO_UPTODATE, &bi->bi_flags); @@ -2781,7 +2781,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, spin_unlock_irq(&sh->stripe_lock); if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags)) wake_up(&conf->wait_for_overlap); - while (bi && bi->bi_sector < + while (bi && bi->bi_iter.bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); @@ -3005,7 +3005,7 @@ static void handle_stripe_clean_event(struct r5conf *conf, clear_bit(R5_UPTODATE, &dev->flags); wbi = dev->written; dev->written = NULL; - while (wbi && wbi->bi_sector < + while (wbi && wbi->bi_iter.bi_sector < dev->sector + STRIPE_SECTORS) { wbi2 = r5_next_bio(wbi, dev->sector); if (!raid5_dec_bi_active_stripes(wbi)) { @@ -4097,7 +4097,7 @@ static int raid5_mergeable_bvec(struct request_queue *q, static int in_chunk_boundary(struct mddev *mddev, struct bio *bio) { - sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); + sector_t sector = bio->bi_iter.bi_sector + get_start_sect(bio->bi_bdev); unsigned int chunk_sectors = mddev->chunk_sectors; unsigned int bio_sectors = bio_sectors(bio); @@ -4234,9 +4234,9 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio) /* * compute position */ - align_bi->bi_sector = raid5_compute_sector(conf, raid_bio->bi_sector, - 0, - &dd_idx, NULL); + align_bi->bi_iter.bi_sector = + raid5_compute_sector(conf, raid_bio->bi_iter.bi_sector, + 0, &dd_idx, NULL); end_sector = bio_end_sector(align_bi); rcu_read_lock(); @@ -4261,7 +4261,8 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio) align_bi->bi_flags &= ~(1 << BIO_SEG_VALID); if (!bio_fits_rdev(align_bi) || - is_badblock(rdev, align_bi->bi_sector, bio_sectors(align_bi), + is_badblock(rdev, align_bi->bi_iter.bi_sector, + bio_sectors(align_bi), &first_bad, &bad_sectors)) { /* too big in some way, or has a known bad block */ bio_put(align_bi); @@ -4270,7 +4271,7 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio) } /* No reshape active, so we can trust rdev->data_offset */ - align_bi->bi_sector += rdev->data_offset; + align_bi->bi_iter.bi_sector += rdev->data_offset; spin_lock_irq(&conf->device_lock); wait_event_lock_irq(conf->wait_for_stripe, @@ -4282,7 +4283,7 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio) if (mddev->gendisk) trace_block_bio_remap(bdev_get_queue(align_bi->bi_bdev), align_bi, disk_devt(mddev->gendisk), - raid_bio->bi_sector); + raid_bio->bi_iter.bi_sector); generic_make_request(align_bi); return 1; } else { @@ -4465,8 +4466,8 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi) /* Skip discard while reshape is happening */ return; - logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); - last_sector = bi->bi_sector + (bi->bi_size>>9); + logical_sector = bi->bi_iter.bi_sector & ~((sector_t)STRIPE_SECTORS-1); + last_sector = bi->bi_iter.bi_sector + (bi->bi_iter.bi_size>>9); bi->bi_next = NULL; bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ @@ -4570,7 +4571,7 @@ static void make_request(struct mddev *mddev, struct bio * bi) return; } - logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1); + logical_sector = bi->bi_iter.bi_sector & ~((sector_t)STRIPE_SECTORS-1); last_sector = bio_end_sector(bi); bi->bi_next = NULL; bi->bi_phys_segments = 1; /* over-loaded to count active stripes */ @@ -5054,7 +5055,8 @@ static int retry_aligned_read(struct r5conf *conf, struct bio *raid_bio) int remaining; int handled = 0; - logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1); + logical_sector = raid_bio->bi_iter.bi_sector & + ~((sector_t)STRIPE_SECTORS-1); sector = raid5_compute_sector(conf, logical_sector, 0, &dd_idx, NULL); last_sector = bio_end_sector(raid_bio); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 6eca019bcf30..16814a8457f8 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -819,7 +819,8 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) dev_info = bio->bi_bdev->bd_disk->private_data; if (dev_info == NULL) goto fail; - if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0) + if ((bio->bi_iter.bi_sector & 7) != 0 || + (bio->bi_iter.bi_size & 4095) != 0) /* Request is not page-aligned. */ goto fail; if (bio_end_sector(bio) > get_capacity(bio->bi_bdev->bd_disk)) { @@ -842,7 +843,7 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) } } - index = (bio->bi_sector >> 3); + index = (bio->bi_iter.bi_sector >> 3); bio_for_each_segment(bvec, bio, i) { page_addr = (unsigned long) page_address(bvec->bv_page) + bvec->bv_offset; diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 464dd29d06c0..dd4e73fdb323 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -190,15 +190,16 @@ static void xpram_make_request(struct request_queue *q, struct bio *bio) unsigned long bytes; int i; - if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0) + if ((bio->bi_iter.bi_sector & 7) != 0 || + (bio->bi_iter.bi_size & 4095) != 0) /* Request is not page-aligned. */ goto fail; - if ((bio->bi_size >> 12) > xdev->size) + if ((bio->bi_iter.bi_size >> 12) > xdev->size) /* Request size is no page-aligned. */ goto fail; - if ((bio->bi_sector >> 3) > 0xffffffffU - xdev->offset) + if ((bio->bi_iter.bi_sector >> 3) > 0xffffffffU - xdev->offset) goto fail; - index = (bio->bi_sector >> 3) + xdev->offset; + index = (bio->bi_iter.bi_sector >> 3) + xdev->offset; bio_for_each_segment(bvec, bio, i) { page_addr = (unsigned long) kmap(bvec->bv_page) + bvec->bv_offset; diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index aa66361ed44b..bac04c2335aa 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c @@ -731,7 +731,7 @@ static int _osd_req_list_objects(struct osd_request *or, bio->bi_rw &= ~REQ_WRITE; or->in.bio = bio; - or->in.total_bytes = bio->bi_size; + or->in.total_bytes = bio->bi_iter.bi_size; return 0; } diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c index e2421ea61352..53741be754b4 100644 --- a/drivers/staging/lustre/lustre/llite/lloop.c +++ b/drivers/staging/lustre/lustre/llite/lloop.c @@ -220,7 +220,7 @@ static int do_bio_lustrebacked(struct lloop_device *lo, struct bio *head) for (bio = head; bio != NULL; bio = bio->bi_next) { LASSERT(rw == bio->bi_rw); - offset = (pgoff_t)(bio->bi_sector << 9) + lo->lo_offset; + offset = (pgoff_t)(bio->bi_iter.bi_sector << 9) + lo->lo_offset; bio_for_each_segment(bvec, bio, i) { BUG_ON(bvec->bv_offset != 0); BUG_ON(bvec->bv_len != PAGE_CACHE_SIZE); @@ -313,7 +313,8 @@ static unsigned int loop_get_bio(struct lloop_device *lo, struct bio **req) bio = &lo->lo_bio; while (*bio && (*bio)->bi_rw == rw) { CDEBUG(D_INFO, "bio sector %llu size %u count %u vcnt%u \n", - (unsigned long long)(*bio)->bi_sector, (*bio)->bi_size, + (unsigned long long)(*bio)->bi_iter.bi_sector, + (*bio)->bi_iter.bi_size, page_count, (*bio)->bi_vcnt); if (page_count + (*bio)->bi_vcnt > LLOOP_MAX_SEGMENTS) break; @@ -347,7 +348,8 @@ static void loop_make_request(struct request_queue *q, struct bio *old_bio) goto err; CDEBUG(D_INFO, "submit bio sector %llu size %u\n", - (unsigned long long)old_bio->bi_sector, old_bio->bi_size); + (unsigned long long)old_bio->bi_iter.bi_sector, + old_bio->bi_iter.bi_size); spin_lock_irq(&lo->lo_lock); inactive = (lo->lo_state != LLOOP_BOUND); @@ -367,7 +369,7 @@ static void loop_make_request(struct request_queue *q, struct bio *old_bio) loop_add_bio(lo, old_bio); return; err: - cfs_bio_io_error(old_bio, old_bio->bi_size); + cfs_bio_io_error(old_bio, old_bio->bi_iter.bi_size); } @@ -378,7 +380,7 @@ static inline void loop_handle_bio(struct lloop_device *lo, struct bio *bio) while (bio) { struct bio *tmp = bio->bi_next; bio->bi_next = NULL; - cfs_bio_endio(bio, bio->bi_size, ret); + cfs_bio_endio(bio, bio->bi_iter.bi_size, ret); bio = tmp; } } diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index 79ce363b2ea9..e9e6f984092b 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -171,13 +171,14 @@ static inline int valid_io_request(struct zram *zram, struct bio *bio) u64 start, end, bound; /* unaligned request */ - if (unlikely(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1))) + if (unlikely(bio->bi_iter.bi_sector & + (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1))) return 0; - if (unlikely(bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1))) + if (unlikely(bio->bi_iter.bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1))) return 0; - start = bio->bi_sector; - end = start + (bio->bi_size >> SECTOR_SHIFT); + start = bio->bi_iter.bi_sector; + end = start + (bio->bi_iter.bi_size >> SECTOR_SHIFT); bound = zram->disksize >> SECTOR_SHIFT; /* out of range range */ if (unlikely(start >= bound || end > bound || start > end)) @@ -684,8 +685,9 @@ static void __zram_make_request(struct zram *zram, struct bio *bio, int rw) break; } - index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT; - offset = (bio->bi_sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; + index = bio->bi_iter.bi_sector >> SECTORS_PER_PAGE_SHIFT; + offset = (bio->bi_iter.bi_sector & + (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; bio_for_each_segment(bvec, bio, i) { int max_transfer_size = PAGE_SIZE - offset; diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index c87959f12760..2d29356d0c85 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c @@ -319,7 +319,7 @@ iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num) bio->bi_bdev = ib_dev->ibd_bd; bio->bi_private = cmd; bio->bi_end_io = &iblock_bio_done; - bio->bi_sector = lba; + bio->bi_iter.bi_sector = lba; return bio; } diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index fc60b31453ee..08e3d1388c65 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c @@ -215,9 +215,9 @@ unsigned int bio_integrity_tag_size(struct bio *bio) { struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - BUG_ON(bio->bi_size == 0); + BUG_ON(bio->bi_iter.bi_size == 0); - return bi->tag_size * (bio->bi_size / bi->sector_size); + return bi->tag_size * (bio->bi_iter.bi_size / bi->sector_size); } EXPORT_SYMBOL(bio_integrity_tag_size); @@ -300,7 +300,7 @@ static void bio_integrity_generate(struct bio *bio) struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); struct blk_integrity_exchg bix; struct bio_vec *bv; - sector_t sector = bio->bi_sector; + sector_t sector = bio->bi_iter.bi_sector; unsigned int i, sectors, total; void *prot_buf = bio->bi_integrity->bip_buf; @@ -387,7 +387,7 @@ int bio_integrity_prep(struct bio *bio) bip->bip_owns_buf = 1; bip->bip_buf = buf; bip->bip_size = len; - bip->bip_sector = bio->bi_sector; + bip->bip_sector = bio->bi_iter.bi_sector; /* Map it */ offset = offset_in_page(buf); diff --git a/fs/bio.c b/fs/bio.c index 33d79a4eb92d..a402ad6e753f 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -532,13 +532,13 @@ void __bio_clone(struct bio *bio, struct bio *bio_src) * most users will be overriding ->bi_bdev with a new target, * so we don't set nor calculate new physical/hw segment counts here */ - bio->bi_sector = bio_src->bi_sector; + bio->bi_iter.bi_sector = bio_src->bi_iter.bi_sector; bio->bi_bdev = bio_src->bi_bdev; bio->bi_flags |= 1 << BIO_CLONED; bio->bi_rw = bio_src->bi_rw; bio->bi_vcnt = bio_src->bi_vcnt; - bio->bi_size = bio_src->bi_size; - bio->bi_idx = bio_src->bi_idx; + bio->bi_iter.bi_size = bio_src->bi_iter.bi_size; + bio->bi_iter.bi_idx = bio_src->bi_iter.bi_idx; } EXPORT_SYMBOL(__bio_clone); @@ -612,7 +612,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page if (unlikely(bio_flagged(bio, BIO_CLONED))) return 0; - if (((bio->bi_size + len) >> 9) > max_sectors) + if (((bio->bi_iter.bi_size + len) >> 9) > max_sectors) return 0; /* @@ -635,8 +635,9 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page simulate merging updated prev_bvec as new bvec. */ .bi_bdev = bio->bi_bdev, - .bi_sector = bio->bi_sector, - .bi_size = bio->bi_size - prev_bv_len, + .bi_sector = bio->bi_iter.bi_sector, + .bi_size = bio->bi_iter.bi_size - + prev_bv_len, .bi_rw = bio->bi_rw, }; @@ -684,8 +685,8 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page if (q->merge_bvec_fn) { struct bvec_merge_data bvm = { .bi_bdev = bio->bi_bdev, - .bi_sector = bio->bi_sector, - .bi_size = bio->bi_size, + .bi_sector = bio->bi_iter.bi_sector, + .bi_size = bio->bi_iter.bi_size, .bi_rw = bio->bi_rw, }; @@ -708,7 +709,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page bio->bi_vcnt++; bio->bi_phys_segments++; done: - bio->bi_size += len; + bio->bi_iter.bi_size += len; return len; } @@ -807,22 +808,22 @@ void bio_advance(struct bio *bio, unsigned bytes) if (bio_integrity(bio)) bio_integrity_advance(bio, bytes); - bio->bi_sector += bytes >> 9; - bio->bi_size -= bytes; + bio->bi_iter.bi_sector += bytes >> 9; + bio->bi_iter.bi_size -= bytes; if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK) return; while (bytes) { - if (unlikely(bio->bi_idx >= bio->bi_vcnt)) { + if (unlikely(bio->bi_iter.bi_idx >= bio->bi_vcnt)) { WARN_ONCE(1, "bio idx %d >= vcnt %d\n", - bio->bi_idx, bio->bi_vcnt); + bio->bi_iter.bi_idx, bio->bi_vcnt); break; } if (bytes >= bio_iovec(bio)->bv_len) { bytes -= bio_iovec(bio)->bv_len; - bio->bi_idx++; + bio->bi_iter.bi_idx++; } else { bio_iovec(bio)->bv_len -= bytes; bio_iovec(bio)->bv_offset += bytes; @@ -1485,7 +1486,7 @@ struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len, if (IS_ERR(bio)) return bio; - if (bio->bi_size == len) + if (bio->bi_iter.bi_size == len) return bio; /* @@ -1763,16 +1764,16 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors) return bp; trace_block_split(bdev_get_queue(bi->bi_bdev), bi, - bi->bi_sector + first_sectors); + bi->bi_iter.bi_sector + first_sectors); BUG_ON(bio_segments(bi) > 1); atomic_set(&bp->cnt, 3); bp->error = 0; bp->bio1 = *bi; bp->bio2 = *bi; - bp->bio2.bi_sector += first_sectors; - bp->bio2.bi_size -= first_sectors << 9; - bp->bio1.bi_size = first_sectors << 9; + bp->bio2.bi_iter.bi_sector += first_sectors; + bp->bio2.bi_iter.bi_size -= first_sectors << 9; + bp->bio1.bi_iter.bi_size = first_sectors << 9; if (bi->bi_vcnt != 0) { bp->bv1 = *bio_iovec(bi); @@ -1821,21 +1822,22 @@ void bio_trim(struct bio *bio, int offset, int size) int sofar = 0; size <<= 9; - if (offset == 0 && size == bio->bi_size) + if (offset == 0 && size == bio->bi_iter.bi_size) return; clear_bit(BIO_SEG_VALID, &bio->bi_flags); bio_advance(bio, offset << 9); - bio->bi_size = size; + bio->bi_iter.bi_size = size; /* avoid any complications with bi_idx being non-zero*/ - if (bio->bi_idx) { - memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_idx, - (bio->bi_vcnt - bio->bi_idx) * sizeof(struct bio_vec)); - bio->bi_vcnt -= bio->bi_idx; - bio->bi_idx = 0; + if (bio->bi_iter.bi_idx) { + memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_iter.bi_idx, + (bio->bi_vcnt - bio->bi_iter.bi_idx) * + sizeof(struct bio_vec)); + bio->bi_vcnt -= bio->bi_iter.bi_idx; + bio->bi_iter.bi_idx = 0; } /* Make sure vcnt and last bv are not too big */ bio_for_each_segment(bvec, bio, i) { @@ -1871,7 +1873,7 @@ sector_t bio_sector_offset(struct bio *bio, unsigned short index, sector_sz = queue_logical_block_size(bio->bi_bdev->bd_disk->queue); sectors = 0; - if (index >= bio->bi_idx) + if (index >= bio->bi_iter.bi_idx) index = bio->bi_vcnt - 1; bio_for_each_segment_all(bv, bio, i) { diff --git a/fs/btrfs/check-integrity.c b/fs/btrfs/check-integrity.c index 131d82800b3a..cb05e1c842c5 100644 --- a/fs/btrfs/check-integrity.c +++ b/fs/btrfs/check-integrity.c @@ -1695,7 +1695,7 @@ static int btrfsic_read_block(struct btrfsic_state *state, return -1; } bio->bi_bdev = block_ctx->dev->bdev; - bio->bi_sector = dev_bytenr >> 9; + bio->bi_iter.bi_sector = dev_bytenr >> 9; for (j = i; j < num_pages; j++) { ret = bio_add_page(bio, block_ctx->pagev[j], @@ -3013,7 +3013,7 @@ static void __btrfsic_submit_bio(int rw, struct bio *bio) int bio_is_patched; char **mapped_datav; - dev_bytenr = 512 * bio->bi_sector; + dev_bytenr = 512 * bio->bi_iter.bi_sector; bio_is_patched = 0; if (dev_state->state->print_mask & BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH) @@ -3021,8 +3021,8 @@ static void __btrfsic_submit_bio(int rw, struct bio *bio) "submit_bio(rw=0x%x, bi_vcnt=%u," " bi_sector=%llu (bytenr %llu), bi_bdev=%p)\n", rw, bio->bi_vcnt, - (unsigned long long)bio->bi_sector, dev_bytenr, - bio->bi_bdev); + (unsigned long long)bio->bi_iter.bi_sector, + dev_bytenr, bio->bi_bdev); mapped_datav = kmalloc(sizeof(*mapped_datav) * bio->bi_vcnt, GFP_NOFS); diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index eac6784e43d7..f5cdeb4b5538 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c @@ -172,7 +172,8 @@ static void end_compressed_bio_read(struct bio *bio, int err) goto out; inode = cb->inode; - ret = check_compressed_csum(inode, cb, (u64)bio->bi_sector << 9); + ret = check_compressed_csum(inode, cb, + (u64)bio->bi_iter.bi_sector << 9); if (ret) goto csum_failed; @@ -370,7 +371,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, for (pg_index = 0; pg_index < cb->nr_pages; pg_index++) { page = compressed_pages[pg_index]; page->mapping = inode->i_mapping; - if (bio->bi_size) + if (bio->bi_iter.bi_size) ret = io_tree->ops->merge_bio_hook(WRITE, page, 0, PAGE_CACHE_SIZE, bio, 0); @@ -504,7 +505,7 @@ static noinline int add_ra_bio_pages(struct inode *inode, if (!em || last_offset < em->start || (last_offset + PAGE_CACHE_SIZE > extent_map_end(em)) || - (em->block_start >> 9) != cb->orig_bio->bi_sector) { + (em->block_start >> 9) != cb->orig_bio->bi_iter.bi_sector) { free_extent_map(em); unlock_extent(tree, last_offset, end); unlock_page(page); @@ -550,7 +551,7 @@ next: * in it. We don't actually do IO on those pages but allocate new ones * to hold the compressed pages on disk. * - * bio->bi_sector points to the compressed extent on disk + * bio->bi_iter.bi_sector points to the compressed extent on disk * bio->bi_io_vec points to all of the inode pages * bio->bi_vcnt is a count of pages * @@ -571,7 +572,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, struct page *page; struct block_device *bdev; struct bio *comp_bio; - u64 cur_disk_byte = (u64)bio->bi_sector << 9; + u64 cur_disk_byte = (u64)bio->bi_iter.bi_sector << 9; u64 em_len; u64 em_start; struct extent_map *em; @@ -657,7 +658,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, page->mapping = inode->i_mapping; page->index = em_start >> PAGE_CACHE_SHIFT; - if (comp_bio->bi_size) + if (comp_bio->bi_iter.bi_size) ret = tree->ops->merge_bio_hook(READ, page, 0, PAGE_CACHE_SIZE, comp_bio, 0); @@ -685,8 +686,8 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, comp_bio, sums); BUG_ON(ret); /* -ENOMEM */ } - sums += (comp_bio->bi_size + root->sectorsize - 1) / - root->sectorsize; + sums += (comp_bio->bi_iter.bi_size + + root->sectorsize - 1) / root->sectorsize; ret = btrfs_map_bio(root, READ, comp_bio, mirror_num, 0); diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 8b5f9e1d1f0e..bcb6f1b780d6 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -1984,7 +1984,7 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start, bio = btrfs_io_bio_alloc(GFP_NOFS, 1); if (!bio) return -EIO; - bio->bi_size = 0; + bio->bi_iter.bi_size = 0; map_length = length; ret = btrfs_map_block(fs_info, WRITE, logical, @@ -1995,7 +1995,7 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start, } BUG_ON(mirror_num != bbio->mirror_num); sector = bbio->stripes[mirror_num-1].physical >> 9; - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; dev = bbio->stripes[mirror_num-1].dev; kfree(bbio); if (!dev || !dev->bdev || !dev->writeable) { @@ -2268,9 +2268,9 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset, return -EIO; } bio->bi_end_io = failed_bio->bi_end_io; - bio->bi_sector = failrec->logical >> 9; + bio->bi_iter.bi_sector = failrec->logical >> 9; bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; - bio->bi_size = 0; + bio->bi_iter.bi_size = 0; btrfs_failed_bio = btrfs_io_bio(failed_bio); if (btrfs_failed_bio->csum) { @@ -2412,7 +2412,7 @@ static void end_bio_extent_readpage(struct bio *bio, int err) struct inode *inode = page->mapping->host; pr_debug("end_bio_extent_readpage: bi_sector=%llu, err=%d, " - "mirror=%lu\n", (u64)bio->bi_sector, err, + "mirror=%lu\n", (u64)bio->bi_iter.bi_sector, err, io_bio->mirror_num); tree = &BTRFS_I(inode)->io_tree; @@ -2543,7 +2543,7 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, if (bio) { bio->bi_bdev = bdev; - bio->bi_sector = first_sector; + bio->bi_iter.bi_sector = first_sector; btrfs_bio = btrfs_io_bio(bio); btrfs_bio->csum = NULL; btrfs_bio->csum_allocated = NULL; @@ -2637,7 +2637,7 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree, if (bio_ret && *bio_ret) { bio = *bio_ret; if (old_compressed) - contig = bio->bi_sector == sector; + contig = bio->bi_iter.bi_sector == sector; else contig = bio_end_sector(bio) == sector; diff --git a/fs/btrfs/file-item.c b/fs/btrfs/file-item.c index 6f3848860283..84a46a42d262 100644 --- a/fs/btrfs/file-item.c +++ b/fs/btrfs/file-item.c @@ -182,7 +182,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, if (!path) return -ENOMEM; - nblocks = bio->bi_size >> inode->i_sb->s_blocksize_bits; + nblocks = bio->bi_iter.bi_size >> inode->i_sb->s_blocksize_bits; if (!dst) { if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) { btrfs_bio->csum_allocated = kmalloc(nblocks * csum_size, @@ -201,7 +201,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, csum = (u8 *)dst; } - if (bio->bi_size > PAGE_CACHE_SIZE * 8) + if (bio->bi_iter.bi_size > PAGE_CACHE_SIZE * 8) path->reada = 2; WARN_ON(bio->bi_vcnt <= 0); @@ -217,7 +217,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root, path->skip_locking = 1; } - disk_bytenr = (u64)bio->bi_sector << 9; + disk_bytenr = (u64)bio->bi_iter.bi_sector << 9; if (dio) offset = logical_offset; while (bio_index < bio->bi_vcnt) { @@ -302,7 +302,7 @@ int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, struct btrfs_dio_private *dip, struct bio *bio, u64 offset) { - int len = (bio->bi_sector << 9) - dip->disk_bytenr; + int len = (bio->bi_iter.bi_sector << 9) - dip->disk_bytenr; u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); int ret; @@ -447,11 +447,12 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, u64 offset; WARN_ON(bio->bi_vcnt <= 0); - sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS); + sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_iter.bi_size), + GFP_NOFS); if (!sums) return -ENOMEM; - sums->len = bio->bi_size; + sums->len = bio->bi_iter.bi_size; INIT_LIST_HEAD(&sums->list); if (contig) @@ -461,7 +462,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, ordered = btrfs_lookup_ordered_extent(inode, offset); BUG_ON(!ordered); /* Logic error */ - sums->bytenr = (u64)bio->bi_sector << 9; + sums->bytenr = (u64)bio->bi_iter.bi_sector << 9; index = 0; while (bio_index < bio->bi_vcnt) { @@ -476,7 +477,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, btrfs_add_ordered_sum(inode, ordered, sums); btrfs_put_ordered_extent(ordered); - bytes_left = bio->bi_size - total_bytes; + bytes_left = bio->bi_iter.bi_size - total_bytes; sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left), GFP_NOFS); @@ -484,7 +485,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, sums->len = bytes_left; ordered = btrfs_lookup_ordered_extent(inode, offset); BUG_ON(!ordered); /* Logic error */ - sums->bytenr = ((u64)bio->bi_sector << 9) + + sums->bytenr = ((u64)bio->bi_iter.bi_sector << 9) + total_bytes; index = 0; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index d6630dc130ba..7ab0e94ad492 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -1577,7 +1577,7 @@ int btrfs_merge_bio_hook(int rw, struct page *page, unsigned long offset, unsigned long bio_flags) { struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; - u64 logical = (u64)bio->bi_sector << 9; + u64 logical = (u64)bio->bi_iter.bi_sector << 9; u64 length = 0; u64 map_length; int ret; @@ -1585,7 +1585,7 @@ int btrfs_merge_bio_hook(int rw, struct page *page, unsigned long offset, if (bio_flags & EXTENT_BIO_COMPRESSED) return 0; - length = bio->bi_size; + length = bio->bi_iter.bi_size; map_length = length; ret = btrfs_map_block(root->fs_info, rw, logical, &map_length, NULL, 0); @@ -6894,7 +6894,8 @@ static void btrfs_end_dio_bio(struct bio *bio, int err) printk(KERN_ERR "btrfs direct IO failed ino %llu rw %lu " "sector %#Lx len %u err no %d\n", btrfs_ino(dip->inode), bio->bi_rw, - (unsigned long long)bio->bi_sector, bio->bi_size, err); + (unsigned long long)bio->bi_iter.bi_sector, + bio->bi_iter.bi_size, err); dip->errors = 1; /* @@ -6985,7 +6986,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, struct bio *bio; struct bio *orig_bio = dip->orig_bio; struct bio_vec *bvec = orig_bio->bi_io_vec; - u64 start_sector = orig_bio->bi_sector; + u64 start_sector = orig_bio->bi_iter.bi_sector; u64 file_offset = dip->logical_offset; u64 submit_len = 0; u64 map_length; @@ -6993,7 +6994,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, int ret = 0; int async_submit = 0; - map_length = orig_bio->bi_size; + map_length = orig_bio->bi_iter.bi_size; ret = btrfs_map_block(root->fs_info, rw, start_sector << 9, &map_length, NULL, 0); if (ret) { @@ -7001,7 +7002,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, return -EIO; } - if (map_length >= orig_bio->bi_size) { + if (map_length >= orig_bio->bi_iter.bi_size) { bio = orig_bio; goto submit; } @@ -7053,7 +7054,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip, bio->bi_private = dip; bio->bi_end_io = btrfs_end_dio_bio; - map_length = orig_bio->bi_size; + map_length = orig_bio->bi_iter.bi_size; ret = btrfs_map_block(root->fs_info, rw, start_sector << 9, &map_length, NULL, 0); @@ -7111,7 +7112,8 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio, if (!skip_sum && !write) { csum_size = btrfs_super_csum_size(root->fs_info->super_copy); - sum_len = dio_bio->bi_size >> inode->i_sb->s_blocksize_bits; + sum_len = dio_bio->bi_iter.bi_size >> + inode->i_sb->s_blocksize_bits; sum_len *= csum_size; } else { sum_len = 0; @@ -7126,8 +7128,8 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio, dip->private = dio_bio->bi_private; dip->inode = inode; dip->logical_offset = file_offset; - dip->bytes = dio_bio->bi_size; - dip->disk_bytenr = (u64)dio_bio->bi_sector << 9; + dip->bytes = dio_bio->bi_iter.bi_size; + dip->disk_bytenr = (u64)dio_bio->bi_iter.bi_sector << 9; io_bio->bi_private = dip; dip->errors = 0; dip->orig_bio = io_bio; diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c index 24ac21840a9a..9af0b25d991a 100644 --- a/fs/btrfs/raid56.c +++ b/fs/btrfs/raid56.c @@ -1032,8 +1032,8 @@ static int rbio_add_io_page(struct btrfs_raid_bio *rbio, /* see if we can add this page onto our existing bio */ if (last) { - last_end = (u64)last->bi_sector << 9; - last_end += last->bi_size; + last_end = (u64)last->bi_iter.bi_sector << 9; + last_end += last->bi_iter.bi_size; /* * we can't merge these if they are from different @@ -1053,9 +1053,9 @@ static int rbio_add_io_page(struct btrfs_raid_bio *rbio, if (!bio) return -ENOMEM; - bio->bi_size = 0; + bio->bi_iter.bi_size = 0; bio->bi_bdev = stripe->dev->bdev; - bio->bi_sector = disk_start >> 9; + bio->bi_iter.bi_sector = disk_start >> 9; set_bit(BIO_UPTODATE, &bio->bi_flags); bio_add_page(bio, page, PAGE_CACHE_SIZE, 0); @@ -1111,7 +1111,7 @@ static void index_rbio_pages(struct btrfs_raid_bio *rbio) spin_lock_irq(&rbio->bio_list_lock); bio_list_for_each(bio, &rbio->bio_list) { - start = (u64)bio->bi_sector << 9; + start = (u64)bio->bi_iter.bi_sector << 9; stripe_offset = start - rbio->raid_map[0]; page_index = stripe_offset >> PAGE_CACHE_SHIFT; @@ -1272,7 +1272,7 @@ cleanup: static int find_bio_stripe(struct btrfs_raid_bio *rbio, struct bio *bio) { - u64 physical = bio->bi_sector; + u64 physical = bio->bi_iter.bi_sector; u64 stripe_start; int i; struct btrfs_bio_stripe *stripe; @@ -1298,7 +1298,7 @@ static int find_bio_stripe(struct btrfs_raid_bio *rbio, static int find_logical_bio_stripe(struct btrfs_raid_bio *rbio, struct bio *bio) { - u64 logical = bio->bi_sector; + u64 logical = bio->bi_iter.bi_sector; u64 stripe_start; int i; @@ -1602,8 +1602,8 @@ static int plug_cmp(void *priv, struct list_head *a, struct list_head *b) plug_list); struct btrfs_raid_bio *rb = container_of(b, struct btrfs_raid_bio, plug_list); - u64 a_sector = ra->bio_list.head->bi_sector; - u64 b_sector = rb->bio_list.head->bi_sector; + u64 a_sector = ra->bio_list.head->bi_iter.bi_sector; + u64 b_sector = rb->bio_list.head->bi_iter.bi_sector; if (a_sector < b_sector) return -1; @@ -1691,7 +1691,7 @@ int raid56_parity_write(struct btrfs_root *root, struct bio *bio, if (IS_ERR(rbio)) return PTR_ERR(rbio); bio_list_add(&rbio->bio_list, bio); - rbio->bio_list_bytes = bio->bi_size; + rbio->bio_list_bytes = bio->bi_iter.bi_size; /* * don't plug on full rbios, just get them out the door @@ -2044,7 +2044,7 @@ int raid56_parity_recover(struct btrfs_root *root, struct bio *bio, rbio->read_rebuild = 1; bio_list_add(&rbio->bio_list, bio); - rbio->bio_list_bytes = bio->bi_size; + rbio->bio_list_bytes = bio->bi_iter.bi_size; rbio->faila = find_logical_bio_stripe(rbio, bio); if (rbio->faila == -1) { diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 1fd3f33c330a..bb9a928fa3a8 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -1308,7 +1308,7 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info, continue; } bio->bi_bdev = page->dev->bdev; - bio->bi_sector = page->physical >> 9; + bio->bi_iter.bi_sector = page->physical >> 9; bio_add_page(bio, page->page, PAGE_SIZE, 0); if (btrfsic_submit_bio_wait(READ, bio)) @@ -1427,7 +1427,7 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, if (!bio) return -EIO; bio->bi_bdev = page_bad->dev->bdev; - bio->bi_sector = page_bad->physical >> 9; + bio->bi_iter.bi_sector = page_bad->physical >> 9; ret = bio_add_page(bio, page_good->page, PAGE_SIZE, 0); if (PAGE_SIZE != ret) { @@ -1520,7 +1520,7 @@ again: bio->bi_private = sbio; bio->bi_end_io = scrub_wr_bio_end_io; bio->bi_bdev = sbio->dev->bdev; - bio->bi_sector = sbio->physical >> 9; + bio->bi_iter.bi_sector = sbio->physical >> 9; sbio->err = 0; } else if (sbio->physical + sbio->page_count * PAGE_SIZE != spage->physical_for_dev_replace || @@ -1926,7 +1926,7 @@ again: bio->bi_private = sbio; bio->bi_end_io = scrub_bio_end_io; bio->bi_bdev = sbio->dev->bdev; - bio->bi_sector = sbio->physical >> 9; + bio->bi_iter.bi_sector = sbio->physical >> 9; sbio->err = 0; } else if (sbio->physical + sbio->page_count * PAGE_SIZE != spage->physical || @@ -3371,8 +3371,8 @@ static int write_page_nocow(struct scrub_ctx *sctx, spin_unlock(&sctx->stat_lock); return -ENOMEM; } - bio->bi_size = 0; - bio->bi_sector = physical_for_dev_replace >> 9; + bio->bi_iter.bi_size = 0; + bio->bi_iter.bi_sector = physical_for_dev_replace >> 9; bio->bi_bdev = dev->bdev; ret = bio_add_page(bio, page, PAGE_CACHE_SIZE, 0); if (ret != PAGE_CACHE_SIZE) { diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 92303f42baaa..f2130de0ddc2 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5411,7 +5411,7 @@ static int bio_size_ok(struct block_device *bdev, struct bio *bio, if (!q->merge_bvec_fn) return 1; - bvm.bi_size = bio->bi_size - prev->bv_len; + bvm.bi_size = bio->bi_iter.bi_size - prev->bv_len; if (q->merge_bvec_fn(q, &bvm, prev) < prev->bv_len) return 0; return 1; @@ -5426,7 +5426,7 @@ static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio, bio->bi_private = bbio; btrfs_io_bio(bio)->stripe_index = dev_nr; bio->bi_end_io = btrfs_end_bio; - bio->bi_sector = physical >> 9; + bio->bi_iter.bi_sector = physical >> 9; #ifdef DEBUG { struct rcu_string *name; @@ -5464,7 +5464,7 @@ again: while (bvec <= (first_bio->bi_io_vec + first_bio->bi_vcnt - 1)) { if (bio_add_page(bio, bvec->bv_page, bvec->bv_len, bvec->bv_offset) < bvec->bv_len) { - u64 len = bio->bi_size; + u64 len = bio->bi_iter.bi_size; atomic_inc(&bbio->stripes_pending); submit_stripe_bio(root, bbio, bio, physical, dev_nr, @@ -5486,7 +5486,7 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) bio->bi_private = bbio->private; bio->bi_end_io = bbio->end_io; btrfs_io_bio(bio)->mirror_num = bbio->mirror_num; - bio->bi_sector = logical >> 9; + bio->bi_iter.bi_sector = logical >> 9; kfree(bbio); bio_endio(bio, -EIO); } @@ -5497,7 +5497,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, { struct btrfs_device *dev; struct bio *first_bio = bio; - u64 logical = (u64)bio->bi_sector << 9; + u64 logical = (u64)bio->bi_iter.bi_sector << 9; u64 length = 0; u64 map_length; u64 *raid_map = NULL; @@ -5506,7 +5506,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio, int total_devs = 1; struct btrfs_bio *bbio = NULL; - length = bio->bi_size; + length = bio->bi_iter.bi_size; map_length = length; ret = __btrfs_map_block(root->fs_info, rw, logical, &map_length, &bbio, diff --git a/fs/buffer.c b/fs/buffer.c index 6024877335ca..1c04ec66974e 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -2982,11 +2982,11 @@ static void guard_bh_eod(int rw, struct bio *bio, struct buffer_head *bh) * let it through, and the IO layer will turn it into * an EIO. */ - if (unlikely(bio->bi_sector >= maxsector)) + if (unlikely(bio->bi_iter.bi_sector >= maxsector)) return; - maxsector -= bio->bi_sector; - bytes = bio->bi_size; + maxsector -= bio->bi_iter.bi_sector; + bytes = bio->bi_iter.bi_size; if (likely((bytes >> 9) <= maxsector)) return; @@ -2994,7 +2994,7 @@ static void guard_bh_eod(int rw, struct bio *bio, struct buffer_head *bh) bytes = maxsector << 9; /* Truncate the bio.. */ - bio->bi_size = bytes; + bio->bi_iter.bi_size = bytes; bio->bi_io_vec[0].bv_len = bytes; /* ..and clear the end of the buffer for reads */ @@ -3029,14 +3029,14 @@ int _submit_bh(int rw, struct buffer_head *bh, unsigned long bio_flags) */ bio = bio_alloc(GFP_NOIO, 1); - bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); + bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_bdev = bh->b_bdev; bio->bi_io_vec[0].bv_page = bh->b_page; bio->bi_io_vec[0].bv_len = bh->b_size; bio->bi_io_vec[0].bv_offset = bh_offset(bh); bio->bi_vcnt = 1; - bio->bi_size = bh->b_size; + bio->bi_iter.bi_size = bh->b_size; bio->bi_end_io = end_bio_bh_io_sync; bio->bi_private = bh; diff --git a/fs/direct-io.c b/fs/direct-io.c index 0e04142d5962..160a5489a939 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c @@ -375,7 +375,7 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio, bio = bio_alloc(GFP_KERNEL, nr_vecs); bio->bi_bdev = bdev; - bio->bi_sector = first_sector; + bio->bi_iter.bi_sector = first_sector; if (dio->is_async) bio->bi_end_io = dio_bio_end_aio; else @@ -719,7 +719,7 @@ static inline int dio_send_cur_page(struct dio *dio, struct dio_submit *sdio, if (sdio->bio) { loff_t cur_offset = sdio->cur_page_fs_offset; loff_t bio_next_offset = sdio->logical_offset_in_bio + - sdio->bio->bi_size; + sdio->bio->bi_iter.bi_size; /* * See whether this new request is contiguous with the old. diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index a31e4da14508..ab95508e3d40 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -298,7 +298,7 @@ ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end) static void ext4_end_bio(struct bio *bio, int error) { ext4_io_end_t *io_end = bio->bi_private; - sector_t bi_sector = bio->bi_sector; + sector_t bi_sector = bio->bi_iter.bi_sector; BUG_ON(!io_end); bio->bi_end_io = NULL; @@ -366,7 +366,7 @@ static int io_submit_init_bio(struct ext4_io_submit *io, bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES)); if (!bio) return -ENOMEM; - bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); + bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_bdev = bh->b_bdev; bio->bi_end_io = ext4_end_bio; bio->bi_private = ext4_get_io_end(io->io_end); diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index a4949096cf4c..a2c8de8ba6ce 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -386,7 +386,7 @@ int f2fs_readpage(struct f2fs_sb_info *sbi, struct page *page, bio = f2fs_bio_alloc(bdev, 1); /* Initialize the bio */ - bio->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); + bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); bio->bi_end_io = read_end_io; if (bio_add_page(bio, page, PAGE_CACHE_SIZE, 0) < PAGE_CACHE_SIZE) { diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index a90c6bc0d129..36e8afd8e1e4 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -682,7 +682,7 @@ retry: bio_blocks = MAX_BIO_BLOCKS(max_hw_blocks(sbi)); sbi->bio[type] = f2fs_bio_alloc(bdev, bio_blocks); - sbi->bio[type]->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); + sbi->bio[type]->bi_iter.bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr); sbi->bio[type]->bi_private = priv; /* * The end_io will be assigned at the sumbission phase. diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 010b9fb9fec6..985da945f0b5 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -272,7 +272,7 @@ static struct bio *gfs2_log_alloc_bio(struct gfs2_sbd *sdp, u64 blkno) nrvecs = max(nrvecs/2, 1U); } - bio->bi_sector = blkno * (sb->s_blocksize >> 9); + bio->bi_iter.bi_sector = blkno * (sb->s_blocksize >> 9); bio->bi_bdev = sb->s_bdev; bio->bi_end_io = gfs2_end_log_write; bio->bi_private = sdp; diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 82303b474958..16194da91652 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -224,7 +224,7 @@ static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector, int silent) lock_page(page); bio = bio_alloc(GFP_NOFS, 1); - bio->bi_sector = sector * (sb->s_blocksize >> 9); + bio->bi_iter.bi_sector = sector * (sb->s_blocksize >> 9); bio->bi_bdev = sb->s_bdev; bio_add_page(bio, page, PAGE_SIZE, 0); diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c index e9a97a0d4314..3f999649587f 100644 --- a/fs/hfsplus/wrapper.c +++ b/fs/hfsplus/wrapper.c @@ -63,7 +63,7 @@ int hfsplus_submit_bio(struct super_block *sb, sector_t sector, sector &= ~((io_size >> HFSPLUS_SECTOR_SHIFT) - 1); bio = bio_alloc(GFP_NOIO, 1); - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_bdev = sb->s_bdev; if (!(rw & WRITE) && data) diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 360d27c48887..8d811e02b4b9 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c @@ -1998,20 +1998,20 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp) bio = bio_alloc(GFP_NOFS, 1); - bio->bi_sector = bp->l_blkno << (log->l2bsize - 9); + bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9); bio->bi_bdev = log->bdev; bio->bi_io_vec[0].bv_page = bp->l_page; bio->bi_io_vec[0].bv_len = LOGPSIZE; bio->bi_io_vec[0].bv_offset = bp->l_offset; bio->bi_vcnt = 1; - bio->bi_size = LOGPSIZE; + bio->bi_iter.bi_size = LOGPSIZE; bio->bi_end_io = lbmIODone; bio->bi_private = bp; /*check if journaling to disk has been disabled*/ if (log->no_integrity) { - bio->bi_size = 0; + bio->bi_iter.bi_size = 0; lbmIODone(bio, 0); } else { submit_bio(READ_SYNC, bio); @@ -2144,21 +2144,21 @@ static void lbmStartIO(struct lbuf * bp) jfs_info("lbmStartIO\n"); bio = bio_alloc(GFP_NOFS, 1); - bio->bi_sector = bp->l_blkno << (log->l2bsize - 9); + bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9); bio->bi_bdev = log->bdev; bio->bi_io_vec[0].bv_page = bp->l_page; bio->bi_io_vec[0].bv_len = LOGPSIZE; bio->bi_io_vec[0].bv_offset = bp->l_offset; bio->bi_vcnt = 1; - bio->bi_size = LOGPSIZE; + bio->bi_iter.bi_size = LOGPSIZE; bio->bi_end_io = lbmIODone; bio->bi_private = bp; /* check if journaling to disk has been disabled */ if (log->no_integrity) { - bio->bi_size = 0; + bio->bi_iter.bi_size = 0; lbmIODone(bio, 0); } else { submit_bio(WRITE_SYNC, bio); diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c index d165cde0c68d..49ba7ff1bbb9 100644 --- a/fs/jfs/jfs_metapage.c +++ b/fs/jfs/jfs_metapage.c @@ -416,7 +416,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) * count from hitting zero before we're through */ inc_io(page); - if (!bio->bi_size) + if (!bio->bi_iter.bi_size) goto dump_bio; submit_bio(WRITE, bio); nr_underway++; @@ -438,7 +438,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) bio = bio_alloc(GFP_NOFS, 1); bio->bi_bdev = inode->i_sb->s_bdev; - bio->bi_sector = pblock << (inode->i_blkbits - 9); + bio->bi_iter.bi_sector = pblock << (inode->i_blkbits - 9); bio->bi_end_io = metapage_write_end_io; bio->bi_private = page; @@ -452,7 +452,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc) if (bio) { if (bio_add_page(bio, page, bio_bytes, bio_offset) < bio_bytes) goto add_failed; - if (!bio->bi_size) + if (!bio->bi_iter.bi_size) goto dump_bio; submit_bio(WRITE, bio); @@ -517,7 +517,8 @@ static int metapage_readpage(struct file *fp, struct page *page) bio = bio_alloc(GFP_NOFS, 1); bio->bi_bdev = inode->i_sb->s_bdev; - bio->bi_sector = pblock << (inode->i_blkbits - 9); + bio->bi_iter.bi_sector = + pblock << (inode->i_blkbits - 9); bio->bi_end_io = metapage_read_end_io; bio->bi_private = page; len = xlen << inode->i_blkbits; diff --git a/fs/logfs/dev_bdev.c b/fs/logfs/dev_bdev.c index e6df3be3b31b..76279e11982d 100644 --- a/fs/logfs/dev_bdev.c +++ b/fs/logfs/dev_bdev.c @@ -26,9 +26,9 @@ static int sync_request(struct page *page, struct block_device *bdev, int rw) bio_vec.bv_len = PAGE_SIZE; bio_vec.bv_offset = 0; bio.bi_vcnt = 1; - bio.bi_size = PAGE_SIZE; bio.bi_bdev = bdev; - bio.bi_sector = page->index * (PAGE_SIZE >> 9); + bio.bi_iter.bi_sector = page->index * (PAGE_SIZE >> 9); + bio.bi_iter.bi_size = PAGE_SIZE; return submit_bio_wait(rw, &bio); } @@ -92,9 +92,9 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, if (i >= max_pages) { /* Block layer cannot split bios :( */ bio->bi_vcnt = i; - bio->bi_size = i * PAGE_SIZE; + bio->bi_iter.bi_size = i * PAGE_SIZE; bio->bi_bdev = super->s_bdev; - bio->bi_sector = ofs >> 9; + bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = writeseg_end_io; atomic_inc(&super->s_pending_writes); @@ -119,9 +119,9 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index, unlock_page(page); } bio->bi_vcnt = nr_pages; - bio->bi_size = nr_pages * PAGE_SIZE; + bio->bi_iter.bi_size = nr_pages * PAGE_SIZE; bio->bi_bdev = super->s_bdev; - bio->bi_sector = ofs >> 9; + bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = writeseg_end_io; atomic_inc(&super->s_pending_writes); @@ -184,9 +184,9 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, if (i >= max_pages) { /* Block layer cannot split bios :( */ bio->bi_vcnt = i; - bio->bi_size = i * PAGE_SIZE; + bio->bi_iter.bi_size = i * PAGE_SIZE; bio->bi_bdev = super->s_bdev; - bio->bi_sector = ofs >> 9; + bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = erase_end_io; atomic_inc(&super->s_pending_writes); @@ -205,9 +205,9 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index, bio->bi_io_vec[i].bv_offset = 0; } bio->bi_vcnt = nr_pages; - bio->bi_size = nr_pages * PAGE_SIZE; + bio->bi_iter.bi_size = nr_pages * PAGE_SIZE; bio->bi_bdev = super->s_bdev; - bio->bi_sector = ofs >> 9; + bio->bi_iter.bi_sector = ofs >> 9; bio->bi_private = sb; bio->bi_end_io = erase_end_io; atomic_inc(&super->s_pending_writes); diff --git a/fs/mpage.c b/fs/mpage.c index dd6d5878f4d9..4979ffa60aaa 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -93,7 +93,7 @@ mpage_alloc(struct block_device *bdev, if (bio) { bio->bi_bdev = bdev; - bio->bi_sector = first_sector; + bio->bi_iter.bi_sector = first_sector; } return bio; } diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index da768923bf7c..56ff823ca82e 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c @@ -134,8 +134,8 @@ bl_submit_bio(int rw, struct bio *bio) if (bio) { get_parallel(bio->bi_private); dprintk("%s submitting %s bio %u@%llu\n", __func__, - rw == READ ? "read" : "write", - bio->bi_size, (unsigned long long)bio->bi_sector); + rw == READ ? "read" : "write", bio->bi_iter.bi_size, + (unsigned long long)bio->bi_iter.bi_sector); submit_bio(rw, bio); } return NULL; @@ -156,7 +156,8 @@ static struct bio *bl_alloc_init_bio(int npg, sector_t isect, } if (bio) { - bio->bi_sector = isect - be->be_f_offset + be->be_v_offset; + bio->bi_iter.bi_sector = isect - be->be_f_offset + + be->be_v_offset; bio->bi_bdev = be->be_mdev; bio->bi_end_io = end_io; bio->bi_private = par; @@ -511,7 +512,7 @@ bl_do_readpage_sync(struct page *page, struct pnfs_block_extent *be, isect = (page->index << PAGE_CACHE_SECTOR_SHIFT) + (offset / SECTOR_SIZE); - bio->bi_sector = isect - be->be_f_offset + be->be_v_offset; + bio->bi_iter.bi_sector = isect - be->be_f_offset + be->be_v_offset; bio->bi_bdev = be->be_mdev; bio->bi_end_io = bl_read_single_end_io; diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 2d8be51f90dc..dc3a9efdaab8 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c @@ -416,7 +416,8 @@ static struct bio *nilfs_alloc_seg_bio(struct the_nilfs *nilfs, sector_t start, } if (likely(bio)) { bio->bi_bdev = nilfs->ns_bdev; - bio->bi_sector = start << (nilfs->ns_blocksize_bits - 9); + bio->bi_iter.bi_sector = + start << (nilfs->ns_blocksize_bits - 9); } return bio; } diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 73920ffda05b..bf482dfed14f 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -413,7 +413,7 @@ static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg, } /* Must put everything in 512 byte sectors for the bio... */ - bio->bi_sector = (reg->hr_start_block + cs) << (bits - 9); + bio->bi_iter.bi_sector = (reg->hr_start_block + cs) << (bits - 9); bio->bi_bdev = reg->hr_bdev; bio->bi_private = wc; bio->bi_end_io = o2hb_bio_end_io; diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 71c8c9d2b882..1b19b9cd692a 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -407,7 +407,7 @@ xfs_alloc_ioend_bio( struct bio *bio = bio_alloc(GFP_NOIO, nvecs); ASSERT(bio->bi_private == NULL); - bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9); + bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_bdev = bh->b_bdev; return bio; } diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index c7f0b77dcb00..5f3ea443ebbe 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -1255,7 +1255,7 @@ next_chunk: bio = bio_alloc(GFP_NOIO, nr_pages); bio->bi_bdev = bp->b_target->bt_bdev; - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_end_io = xfs_buf_bio_end_io; bio->bi_private = bp; @@ -1277,7 +1277,7 @@ next_chunk: total_nr_pages--; } - if (likely(bio->bi_size)) { + if (likely(bio->bi_iter.bi_size)) { if (xfs_buf_is_vmapped(bp)) { flush_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp)); diff --git a/include/linux/bio.h b/include/linux/bio.h index 060ff695085c..e2e0bc642ed1 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -62,19 +62,19 @@ * on highmem page vectors */ #define bio_iovec_idx(bio, idx) (&((bio)->bi_io_vec[(idx)])) -#define bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_idx) +#define bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) #define bio_page(bio) bio_iovec((bio))->bv_page #define bio_offset(bio) bio_iovec((bio))->bv_offset -#define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_idx) -#define bio_sectors(bio) ((bio)->bi_size >> 9) -#define bio_end_sector(bio) ((bio)->bi_sector + bio_sectors((bio))) +#define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_iter.bi_idx) +#define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) +#define bio_end_sector(bio) ((bio)->bi_iter.bi_sector + bio_sectors((bio))) static inline unsigned int bio_cur_bytes(struct bio *bio) { if (bio->bi_vcnt) return bio_iovec(bio)->bv_len; else /* dataless requests such as discard */ - return bio->bi_size; + return bio->bi_iter.bi_size; } static inline void *bio_data(struct bio *bio) @@ -108,7 +108,7 @@ static inline void *bio_data(struct bio *bio) */ #define __BVEC_END(bio) bio_iovec_idx((bio), (bio)->bi_vcnt - 1) -#define __BVEC_START(bio) bio_iovec_idx((bio), (bio)->bi_idx) +#define __BVEC_START(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) /* Default implementation of BIOVEC_PHYS_MERGEABLE */ #define __BIOVEC_PHYS_MERGEABLE(vec1, vec2) \ @@ -150,7 +150,7 @@ static inline void *bio_data(struct bio *bio) i++) #define bio_for_each_segment(bvl, bio, i) \ - for (i = (bio)->bi_idx; \ + for (i = (bio)->bi_iter.bi_idx; \ bvl = bio_iovec_idx((bio), (i)), i < (bio)->bi_vcnt; \ i++) @@ -365,7 +365,7 @@ static inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx, #define __bio_kunmap_irq(buf, flags) bvec_kunmap_irq(buf, flags) #define bio_kmap_irq(bio, flags) \ - __bio_kmap_irq((bio), (bio)->bi_idx, (flags)) + __bio_kmap_irq((bio), (bio)->bi_iter.bi_idx, (flags)) #define bio_kunmap_irq(buf,flags) __bio_kunmap_irq(buf, flags) /* diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 238ef0ed62f8..29b5b84d8a29 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -28,13 +28,19 @@ struct bio_vec { unsigned int bv_offset; }; +struct bvec_iter { + sector_t bi_sector; /* device address in 512 byte + sectors */ + unsigned int bi_size; /* residual I/O count */ + + unsigned int bi_idx; /* current index into bvl_vec */ +}; + /* * main unit of I/O for the block layer and lower layers (ie drivers and * stacking drivers) */ struct bio { - sector_t bi_sector; /* device address in 512 byte - sectors */ struct bio *bi_next; /* request queue link */ struct block_device *bi_bdev; unsigned long bi_flags; /* status, command, etc */ @@ -42,16 +48,13 @@ struct bio { * top bits priority */ - unsigned short bi_vcnt; /* how many bio_vec's */ - unsigned short bi_idx; /* current index into bvl_vec */ + struct bvec_iter bi_iter; /* Number of segments in this BIO after * physical address coalescing is performed. */ unsigned int bi_phys_segments; - unsigned int bi_size; /* residual I/O count */ - /* * To keep track of the max segment size, we account for the * sizes of the first and last mergeable segments in this bio. @@ -74,11 +77,13 @@ struct bio { struct bio_integrity_payload *bi_integrity; /* data integrity */ #endif + unsigned short bi_vcnt; /* how many bio_vec's */ + /* * Everything starting with bi_max_vecs will be preserved by bio_reset() */ - unsigned int bi_max_vecs; /* max bvl_vecs we can hold */ + unsigned short bi_max_vecs; /* max bvl_vecs we can hold */ atomic_t bi_cnt; /* pin count */ diff --git a/include/trace/events/bcache.h b/include/trace/events/bcache.h index e2b9576d00e2..095c6e4fe1e8 100644 --- a/include/trace/events/bcache.h +++ b/include/trace/events/bcache.h @@ -24,10 +24,10 @@ DECLARE_EVENT_CLASS(bcache_request, __entry->dev = bio->bi_bdev->bd_dev; __entry->orig_major = d->disk->major; __entry->orig_minor = d->disk->first_minor; - __entry->sector = bio->bi_sector; - __entry->orig_sector = bio->bi_sector - 16; - __entry->nr_sector = bio->bi_size >> 9; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + __entry->sector = bio->bi_iter.bi_sector; + __entry->orig_sector = bio->bi_iter.bi_sector - 16; + __entry->nr_sector = bio->bi_iter.bi_size >> 9; + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); ), TP_printk("%d,%d %s %llu + %u (from %d,%d @ %llu)", @@ -99,9 +99,9 @@ DECLARE_EVENT_CLASS(bcache_bio, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; - __entry->nr_sector = bio->bi_size >> 9; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + __entry->sector = bio->bi_iter.bi_sector; + __entry->nr_sector = bio->bi_iter.bi_size >> 9; + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); ), TP_printk("%d,%d %s %llu + %u", @@ -134,9 +134,9 @@ TRACE_EVENT(bcache_read, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; - __entry->nr_sector = bio->bi_size >> 9; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + __entry->sector = bio->bi_iter.bi_sector; + __entry->nr_sector = bio->bi_iter.bi_size >> 9; + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); __entry->cache_hit = hit; __entry->bypass = bypass; ), @@ -162,9 +162,9 @@ TRACE_EVENT(bcache_write, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; - __entry->nr_sector = bio->bi_size >> 9; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + __entry->sector = bio->bi_iter.bi_sector; + __entry->nr_sector = bio->bi_iter.bi_size >> 9; + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); __entry->writeback = writeback; __entry->bypass = bypass; ), diff --git a/include/trace/events/block.h b/include/trace/events/block.h index 4c2301d2ef1a..e76ae19a8d6f 100644 --- a/include/trace/events/block.h +++ b/include/trace/events/block.h @@ -243,9 +243,9 @@ TRACE_EVENT(block_bio_bounce, TP_fast_assign( __entry->dev = bio->bi_bdev ? bio->bi_bdev->bd_dev : 0; - __entry->sector = bio->bi_sector; + __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -280,10 +280,10 @@ TRACE_EVENT(block_bio_complete, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; + __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); __entry->error = error; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); ), TP_printk("%d,%d %s %llu + %u [%d]", @@ -308,9 +308,9 @@ DECLARE_EVENT_CLASS(block_bio_merge, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; + __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -375,9 +375,9 @@ TRACE_EVENT(block_bio_queue, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; + __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -403,7 +403,7 @@ DECLARE_EVENT_CLASS(block_get_rq, TP_fast_assign( __entry->dev = bio ? bio->bi_bdev->bd_dev : 0; - __entry->sector = bio ? bio->bi_sector : 0; + __entry->sector = bio ? bio->bi_iter.bi_sector : 0; __entry->nr_sector = bio ? bio_sectors(bio) : 0; blk_fill_rwbs(__entry->rwbs, bio ? bio->bi_rw : 0, __entry->nr_sector); @@ -538,9 +538,9 @@ TRACE_EVENT(block_split, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; + __entry->sector = bio->bi_iter.bi_sector; __entry->new_sector = new_sector; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); memcpy(__entry->comm, current->comm, TASK_COMM_LEN); ), @@ -579,11 +579,11 @@ TRACE_EVENT(block_bio_remap, TP_fast_assign( __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_sector; + __entry->sector = bio->bi_iter.bi_sector; __entry->nr_sector = bio_sectors(bio); __entry->old_dev = dev; __entry->old_sector = from; - blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size); + blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size); ), TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu", diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index e0dc355fa317..bd3ee4fbe7a7 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -616,8 +616,8 @@ TRACE_EVENT(f2fs_do_submit_bio, __entry->dev = sb->s_dev; __entry->btype = btype; __entry->sync = sync; - __entry->sector = bio->bi_sector; - __entry->size = bio->bi_size; + __entry->sector = bio->bi_iter.bi_sector; + __entry->size = bio->bi_iter.bi_size; ), TP_printk("dev = (%d,%d), type = %s, io = %s, sector = %lld, size = %u", diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c index d09dd10c5a5e..9a58bc258810 100644 --- a/kernel/power/block_io.c +++ b/kernel/power/block_io.c @@ -32,7 +32,7 @@ static int submit(int rw, struct block_device *bdev, sector_t sector, struct bio *bio; bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1); - bio->bi_sector = sector; + bio->bi_iter.bi_sector = sector; bio->bi_bdev = bdev; bio->bi_end_io = end_swap_bio_read; diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c index f785aef65799..b418cb0d7242 100644 --- a/kernel/trace/blktrace.c +++ b/kernel/trace/blktrace.c @@ -781,8 +781,8 @@ static void blk_add_trace_bio(struct request_queue *q, struct bio *bio, if (!error && !bio_flagged(bio, BIO_UPTODATE)) error = EIO; - __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what, - error, 0, NULL); + __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, + bio->bi_rw, what, error, 0, NULL); } static void blk_add_trace_bio_bounce(void *ignore, @@ -885,8 +885,9 @@ static void blk_add_trace_split(void *ignore, if (bt) { __be64 rpdu = cpu_to_be64(pdu); - __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, - BLK_TA_SPLIT, !bio_flagged(bio, BIO_UPTODATE), + __blk_add_trace(bt, bio->bi_iter.bi_sector, + bio->bi_iter.bi_size, bio->bi_rw, BLK_TA_SPLIT, + !bio_flagged(bio, BIO_UPTODATE), sizeof(rpdu), &rpdu); } } @@ -918,9 +919,9 @@ static void blk_add_trace_bio_remap(void *ignore, r.device_to = cpu_to_be32(bio->bi_bdev->bd_dev); r.sector_from = cpu_to_be64(from); - __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, - BLK_TA_REMAP, !bio_flagged(bio, BIO_UPTODATE), - sizeof(r), &r); + __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size, + bio->bi_rw, BLK_TA_REMAP, + !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r); } /** diff --git a/mm/page_io.c b/mm/page_io.c index 8c79a4764be0..f14eded987fa 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -31,13 +31,13 @@ static struct bio *get_swap_bio(gfp_t gfp_flags, bio = bio_alloc(gfp_flags, 1); if (bio) { - bio->bi_sector = map_swap_page(page, &bio->bi_bdev); - bio->bi_sector <<= PAGE_SHIFT - 9; + bio->bi_iter.bi_sector = map_swap_page(page, &bio->bi_bdev); + bio->bi_iter.bi_sector <<= PAGE_SHIFT - 9; bio->bi_io_vec[0].bv_page = page; bio->bi_io_vec[0].bv_len = PAGE_SIZE; bio->bi_io_vec[0].bv_offset = 0; bio->bi_vcnt = 1; - bio->bi_size = PAGE_SIZE; + bio->bi_iter.bi_size = PAGE_SIZE; bio->bi_end_io = end_io; } return bio; @@ -62,7 +62,7 @@ void end_swap_bio_write(struct bio *bio, int err) printk(KERN_ALERT "Write-error on swap-device (%u:%u:%Lu)\n", imajor(bio->bi_bdev->bd_inode), iminor(bio->bi_bdev->bd_inode), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); ClearPageReclaim(page); } end_page_writeback(page); @@ -80,7 +80,7 @@ void end_swap_bio_read(struct bio *bio, int err) printk(KERN_ALERT "Read-error on swap-device (%u:%u:%Lu)\n", imajor(bio->bi_bdev->bd_inode), iminor(bio->bi_bdev->bd_inode), - (unsigned long long)bio->bi_sector); + (unsigned long long)bio->bi_iter.bi_sector); goto out; } -- cgit v1.2.3-59-g8ed1b From a4ad39b1d10584dfcfcfb0d510faab2c7f034399 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Wed, 7 Aug 2013 14:24:32 -0700 Subject: block: Convert bio_iovec() to bvec_iter For immutable biovecs, we'll be introducing a new bio_iovec() that uses our new bvec iterator to construct a biovec, taking into account bvec_iter->bi_bvec_done - this patch updates existing users for the new usage. Some of the existing users really do need a pointer into the bvec array - those uses are all going to be removed, but we'll need the functionality from immutable to remove them - so for now rename the existing bio_iovec() -> __bio_iovec(), and it'll be removed in a couple patches. Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: "Ed L. Cashin" Cc: Alasdair Kergon Cc: dm-devel@redhat.com Cc: "James E.J. Bottomley" --- drivers/block/aoe/aoecmd.c | 2 +- drivers/md/bcache/io.c | 13 +++++++------ drivers/md/dm-verity.c | 2 +- drivers/scsi/sd.c | 2 +- fs/bio.c | 20 ++++++++++---------- include/linux/bio.h | 10 ++++++---- 6 files changed, 26 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 877ba119b3f8..77c24ab1898a 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -932,7 +932,7 @@ bufinit(struct buf *buf, struct request *rq, struct bio *bio) buf->resid = bio->bi_iter.bi_size; buf->sector = bio->bi_iter.bi_sector; bio_pageinc(bio); - buf->bv = bio_iovec(bio); + buf->bv = __bio_iovec(bio); buf->bv_resid = buf->bv->bv_len; WARN_ON(buf->bv_resid == 0); } diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index cc4ba2da5fb6..dc44f0689eb7 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -22,11 +22,12 @@ static void bch_bi_idx_hack_endio(struct bio *bio, int error) static void bch_generic_make_request_hack(struct bio *bio) { if (bio->bi_iter.bi_idx) { + int i; + struct bio_vec *bv; struct bio *clone = bio_alloc(GFP_NOIO, bio_segments(bio)); - memcpy(clone->bi_io_vec, - bio_iovec(bio), - bio_segments(bio) * sizeof(struct bio_vec)); + bio_for_each_segment(bv, bio, i) + clone->bi_io_vec[clone->bi_vcnt++] = *bv; clone->bi_iter.bi_sector = bio->bi_iter.bi_sector; clone->bi_bdev = bio->bi_bdev; @@ -97,7 +98,7 @@ struct bio *bch_bio_split(struct bio *bio, int sectors, if (!ret) return NULL; - memcpy(ret->bi_io_vec, bio_iovec(bio), + memcpy(ret->bi_io_vec, __bio_iovec(bio), sizeof(struct bio_vec) * vcnt); break; @@ -106,7 +107,7 @@ struct bio *bch_bio_split(struct bio *bio, int sectors, if (!ret) return NULL; - memcpy(ret->bi_io_vec, bio_iovec(bio), + memcpy(ret->bi_io_vec, __bio_iovec(bio), sizeof(struct bio_vec) * vcnt); ret->bi_io_vec[vcnt - 1].bv_len = nbytes; @@ -182,7 +183,7 @@ static unsigned bch_bio_max_sectors(struct bio *bio) ret = min(ret, queue_max_sectors(q)); WARN_ON(!ret); - ret = max_t(int, ret, bio_iovec(bio)->bv_len >> 9); + ret = max_t(int, ret, bio_iovec(bio).bv_len >> 9); return ret; } diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index 132b3154d466..5392135924ca 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -524,7 +524,7 @@ static int verity_map(struct dm_target *ti, struct bio *bio) io->io_vec = io->io_vec_inline; else io->io_vec = mempool_alloc(v->vec_mempool, GFP_NOIO); - memcpy(io->io_vec, bio_iovec(bio), + memcpy(io->io_vec, __bio_iovec(bio), io->io_vec_size * sizeof(struct bio_vec)); verity_submit_prefetch(v, io); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e6c4bff04339..200d6bc81240 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -801,7 +801,7 @@ static int sd_setup_write_same_cmnd(struct scsi_device *sdp, struct request *rq) if (sdkp->device->no_write_same) return BLKPREP_KILL; - BUG_ON(bio_offset(bio) || bio_iovec(bio)->bv_len != sdp->sector_size); + BUG_ON(bio_offset(bio) || bio_iovec(bio).bv_len != sdp->sector_size); sector >>= ilog2(sdp->sector_size) - 9; nr_sectors >>= ilog2(sdp->sector_size) - 9; diff --git a/fs/bio.c b/fs/bio.c index a402ad6e753f..7bb281fc3d5c 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -821,12 +821,12 @@ void bio_advance(struct bio *bio, unsigned bytes) break; } - if (bytes >= bio_iovec(bio)->bv_len) { - bytes -= bio_iovec(bio)->bv_len; + if (bytes >= bio_iovec(bio).bv_len) { + bytes -= bio_iovec(bio).bv_len; bio->bi_iter.bi_idx++; } else { - bio_iovec(bio)->bv_len -= bytes; - bio_iovec(bio)->bv_offset += bytes; + bio_iovec(bio).bv_len -= bytes; + bio_iovec(bio).bv_offset += bytes; bytes = 0; } } @@ -879,8 +879,8 @@ void bio_copy_data(struct bio *dst, struct bio *src) unsigned src_offset, dst_offset, bytes; void *src_p, *dst_p; - src_bv = bio_iovec(src); - dst_bv = bio_iovec(dst); + src_bv = __bio_iovec(src); + dst_bv = __bio_iovec(dst); src_offset = src_bv->bv_offset; dst_offset = dst_bv->bv_offset; @@ -893,7 +893,7 @@ void bio_copy_data(struct bio *dst, struct bio *src) if (!src) break; - src_bv = bio_iovec(src); + src_bv = __bio_iovec(src); } src_offset = src_bv->bv_offset; @@ -906,7 +906,7 @@ void bio_copy_data(struct bio *dst, struct bio *src) if (!dst) break; - dst_bv = bio_iovec(dst); + dst_bv = __bio_iovec(dst); } dst_offset = dst_bv->bv_offset; @@ -1776,8 +1776,8 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors) bp->bio1.bi_iter.bi_size = first_sectors << 9; if (bi->bi_vcnt != 0) { - bp->bv1 = *bio_iovec(bi); - bp->bv2 = *bio_iovec(bi); + bp->bv1 = bio_iovec(bi); + bp->bv2 = bio_iovec(bi); if (bio_is_rw(bi)) { bp->bv2.bv_offset += first_sectors << 9; diff --git a/include/linux/bio.h b/include/linux/bio.h index e2e0bc642ed1..9f182fcbe714 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -62,9 +62,11 @@ * on highmem page vectors */ #define bio_iovec_idx(bio, idx) (&((bio)->bi_io_vec[(idx)])) -#define bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) -#define bio_page(bio) bio_iovec((bio))->bv_page -#define bio_offset(bio) bio_iovec((bio))->bv_offset +#define __bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) +#define bio_iovec(bio) (*__bio_iovec(bio)) + +#define bio_page(bio) (bio_iovec((bio)).bv_page) +#define bio_offset(bio) (bio_iovec((bio)).bv_offset) #define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_iter.bi_idx) #define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) #define bio_end_sector(bio) ((bio)->bi_iter.bi_sector + bio_sectors((bio))) @@ -72,7 +74,7 @@ static inline unsigned int bio_cur_bytes(struct bio *bio) { if (bio->bi_vcnt) - return bio_iovec(bio)->bv_len; + return bio_iovec(bio).bv_len; else /* dataless requests such as discard */ return bio->bi_iter.bi_size; } -- cgit v1.2.3-59-g8ed1b From 7988613b0e5b2638caf6cd493cc78e9595eba19c Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sat, 23 Nov 2013 17:19:00 -0800 Subject: block: Convert bio_for_each_segment() to bvec_iter More prep work for immutable biovecs - with immutable bvecs drivers won't be able to use the biovec directly, they'll need to use helpers that take into account bio->bi_iter.bi_bvec_done. This updates callers for the new usage without changing the implementation yet. Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: Geert Uytterhoeven Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: "Ed L. Cashin" Cc: Nick Piggin Cc: Lars Ellenberg Cc: Jiri Kosina Cc: Paul Clements Cc: Jim Paris Cc: Geoff Levand Cc: Yehuda Sadeh Cc: Sage Weil Cc: Alex Elder Cc: ceph-devel@vger.kernel.org Cc: Joshua Morris Cc: Philip Kelleher Cc: Konrad Rzeszutek Wilk Cc: Jeremy Fitzhardinge Cc: Neil Brown Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: linux390@de.ibm.com Cc: Nagalakshmi Nandigama Cc: Sreekanth Reddy Cc: support@lsi.com Cc: "James E.J. Bottomley" Cc: Greg Kroah-Hartman Cc: Alexander Viro Cc: Steven Whitehouse Cc: Herton Ronaldo Krzesinski Cc: Tejun Heo Cc: Andrew Morton Cc: Guo Chao Cc: Asai Thambi S P Cc: Selvan Mani Cc: Sam Bradshaw Cc: Matthew Wilcox Cc: Keith Busch Cc: Stephen Hemminger Cc: Quoc-Son Anh Cc: Sebastian Ott Cc: Nitin Gupta Cc: Minchan Kim Cc: Jerome Marchand Cc: Seth Jennings Cc: "Martin K. Petersen" Cc: Mike Snitzer Cc: Vivek Goyal Cc: "Darrick J. Wong" Cc: Chris Metcalf Cc: Jan Kara Cc: linux-m68k@lists.linux-m68k.org Cc: linuxppc-dev@lists.ozlabs.org Cc: drbd-user@lists.linbit.com Cc: nbd-general@lists.sourceforge.net Cc: cbe-oss-dev@lists.ozlabs.org Cc: xen-devel@lists.xensource.com Cc: virtualization@lists.linux-foundation.org Cc: linux-raid@vger.kernel.org Cc: linux-s390@vger.kernel.org Cc: DL-MPTFusionLinux@lsi.com Cc: linux-scsi@vger.kernel.org Cc: devel@driverdev.osuosl.org Cc: linux-fsdevel@vger.kernel.org Cc: cluster-devel@redhat.com Cc: linux-mm@kvack.org Acked-by: Geoff Levand --- arch/m68k/emu/nfblock.c | 11 ++--- arch/powerpc/sysdev/axonram.c | 18 ++++---- block/blk-core.c | 4 +- block/blk-merge.c | 49 ++++++++++---------- drivers/block/aoe/aoecmd.c | 16 +++---- drivers/block/brd.c | 12 ++--- drivers/block/drbd/drbd_main.c | 27 ++++++----- drivers/block/drbd/drbd_receiver.c | 13 +++--- drivers/block/drbd/drbd_worker.c | 8 ++-- drivers/block/floppy.c | 12 ++--- drivers/block/loop.c | 23 +++++----- drivers/block/mtip32xx/mtip32xx.c | 13 +++--- drivers/block/nbd.c | 12 ++--- drivers/block/nvme-core.c | 33 ++++++++------ drivers/block/ps3disk.c | 10 ++--- drivers/block/ps3vram.c | 10 ++--- drivers/block/rbd.c | 38 ++++++++-------- drivers/block/rsxx/dma.c | 11 ++--- drivers/md/bcache/btree.c | 4 +- drivers/md/bcache/debug.c | 19 ++++---- drivers/md/bcache/io.c | 69 ++++++++++++----------------- drivers/md/bcache/request.c | 26 +++++------ drivers/md/raid5.c | 12 ++--- drivers/s390/block/dasd_diag.c | 10 ++--- drivers/s390/block/dasd_eckd.c | 48 ++++++++++---------- drivers/s390/block/dasd_fba.c | 26 +++++------ drivers/s390/block/dcssblk.c | 16 +++---- drivers/s390/block/scm_blk.c | 8 ++-- drivers/s390/block/scm_blk_cluster.c | 4 +- drivers/s390/block/xpram.c | 10 ++--- drivers/scsi/mpt2sas/mpt2sas_transport.c | 31 ++++++------- drivers/scsi/mpt3sas/mpt3sas_transport.c | 31 ++++++------- drivers/staging/lustre/lustre/llite/lloop.c | 14 +++--- drivers/staging/zram/zram_drv.c | 19 ++++---- fs/bio-integrity.c | 30 +++++++------ fs/bio.c | 22 ++++----- include/linux/bio.h | 28 ++++++------ include/linux/blkdev.h | 7 +-- mm/bounce.c | 44 +++++++++--------- 39 files changed, 401 insertions(+), 397 deletions(-) (limited to 'include/linux') diff --git a/arch/m68k/emu/nfblock.c b/arch/m68k/emu/nfblock.c index 0a9d0b3c794b..2d75ae246167 100644 --- a/arch/m68k/emu/nfblock.c +++ b/arch/m68k/emu/nfblock.c @@ -62,17 +62,18 @@ struct nfhd_device { static void nfhd_make_request(struct request_queue *queue, struct bio *bio) { struct nfhd_device *dev = queue->queuedata; - struct bio_vec *bvec; - int i, dir, len, shift; + struct bio_vec bvec; + struct bvec_iter iter; + int dir, len, shift; sector_t sec = bio->bi_iter.bi_sector; dir = bio_data_dir(bio); shift = dev->bshift; - bio_for_each_segment(bvec, bio, i) { - len = bvec->bv_len; + bio_for_each_segment(bvec, bio, iter) { + len = bvec.bv_len; len >>= 9; nfhd_read_write(dev->id, 0, dir, sec >> shift, len >> shift, - bvec_to_phys(bvec)); + bvec_to_phys(&bvec)); sec += len; } bio_endio(bio, 0); diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index f33bcbaa6a07..47b6b9f81d43 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -109,28 +109,28 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) struct axon_ram_bank *bank = bio->bi_bdev->bd_disk->private_data; unsigned long phys_mem, phys_end; void *user_mem; - struct bio_vec *vec; + struct bio_vec vec; unsigned int transfered; - unsigned short idx; + struct bvec_iter iter; phys_mem = bank->io_addr + (bio->bi_iter.bi_sector << AXON_RAM_SECTOR_SHIFT); phys_end = bank->io_addr + bank->size; transfered = 0; - bio_for_each_segment(vec, bio, idx) { - if (unlikely(phys_mem + vec->bv_len > phys_end)) { + bio_for_each_segment(vec, bio, iter) { + if (unlikely(phys_mem + vec.bv_len > phys_end)) { bio_io_error(bio); return; } - user_mem = page_address(vec->bv_page) + vec->bv_offset; + user_mem = page_address(vec.bv_page) + vec.bv_offset; if (bio_data_dir(bio) == READ) - memcpy(user_mem, (void *) phys_mem, vec->bv_len); + memcpy(user_mem, (void *) phys_mem, vec.bv_len); else - memcpy((void *) phys_mem, user_mem, vec->bv_len); + memcpy((void *) phys_mem, user_mem, vec.bv_len); - phys_mem += vec->bv_len; - transfered += vec->bv_len; + phys_mem += vec.bv_len; + transfered += vec.bv_len; } bio_endio(bio, 0); } diff --git a/block/blk-core.c b/block/blk-core.c index 5c2ab2c74066..5da8e900d3b1 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -2746,10 +2746,10 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq, void rq_flush_dcache_pages(struct request *rq) { struct req_iterator iter; - struct bio_vec *bvec; + struct bio_vec bvec; rq_for_each_segment(bvec, rq, iter) - flush_dcache_page(bvec->bv_page); + flush_dcache_page(bvec.bv_page); } EXPORT_SYMBOL_GPL(rq_flush_dcache_pages); #endif diff --git a/block/blk-merge.c b/block/blk-merge.c index 03bc083c28cf..a1ead9049ed6 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -12,10 +12,11 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q, struct bio *bio) { - struct bio_vec *bv, *bvprv = NULL; - int cluster, i, high, highprv = 1; + struct bio_vec bv, bvprv = { NULL }; + int cluster, high, highprv = 1; unsigned int seg_size, nr_phys_segs; struct bio *fbio, *bbio; + struct bvec_iter iter; if (!bio) return 0; @@ -25,25 +26,23 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q, seg_size = 0; nr_phys_segs = 0; for_each_bio(bio) { - bio_for_each_segment(bv, bio, i) { + bio_for_each_segment(bv, bio, iter) { /* * the trick here is making sure that a high page is * never considered part of another segment, since that * might change with the bounce page. */ - high = page_to_pfn(bv->bv_page) > queue_bounce_pfn(q); - if (high || highprv) - goto new_segment; - if (cluster) { - if (seg_size + bv->bv_len + high = page_to_pfn(bv.bv_page) > queue_bounce_pfn(q); + if (!high && !highprv && cluster) { + if (seg_size + bv.bv_len > queue_max_segment_size(q)) goto new_segment; - if (!BIOVEC_PHYS_MERGEABLE(bvprv, bv)) + if (!BIOVEC_PHYS_MERGEABLE(&bvprv, &bv)) goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bv)) + if (!BIOVEC_SEG_BOUNDARY(q, &bvprv, &bv)) goto new_segment; - seg_size += bv->bv_len; + seg_size += bv.bv_len; bvprv = bv; continue; } @@ -54,7 +53,7 @@ new_segment: nr_phys_segs++; bvprv = bv; - seg_size = bv->bv_len; + seg_size = bv.bv_len; highprv = high; } bbio = bio; @@ -110,21 +109,21 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio, return 0; } -static void +static inline void __blk_segment_map_sg(struct request_queue *q, struct bio_vec *bvec, - struct scatterlist *sglist, struct bio_vec **bvprv, + struct scatterlist *sglist, struct bio_vec *bvprv, struct scatterlist **sg, int *nsegs, int *cluster) { int nbytes = bvec->bv_len; - if (*bvprv && *cluster) { + if (*sg && *cluster) { if ((*sg)->length + nbytes > queue_max_segment_size(q)) goto new_segment; - if (!BIOVEC_PHYS_MERGEABLE(*bvprv, bvec)) + if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, *bvprv, bvec)) + if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec)) goto new_segment; (*sg)->length += nbytes; @@ -150,7 +149,7 @@ new_segment: sg_set_page(*sg, bvec->bv_page, nbytes, bvec->bv_offset); (*nsegs)++; } - *bvprv = bvec; + *bvprv = *bvec; } /* @@ -160,7 +159,7 @@ new_segment: int blk_rq_map_sg(struct request_queue *q, struct request *rq, struct scatterlist *sglist) { - struct bio_vec *bvec, *bvprv; + struct bio_vec bvec, bvprv; struct req_iterator iter; struct scatterlist *sg; int nsegs, cluster; @@ -171,10 +170,9 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq, /* * for each bio in rq */ - bvprv = NULL; sg = NULL; rq_for_each_segment(bvec, rq, iter) { - __blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg, + __blk_segment_map_sg(q, &bvec, sglist, &bvprv, &sg, &nsegs, &cluster); } /* segments in rq */ @@ -223,18 +221,17 @@ EXPORT_SYMBOL(blk_rq_map_sg); int blk_bio_map_sg(struct request_queue *q, struct bio *bio, struct scatterlist *sglist) { - struct bio_vec *bvec, *bvprv; + struct bio_vec bvec, bvprv; struct scatterlist *sg; int nsegs, cluster; - unsigned long i; + struct bvec_iter iter; nsegs = 0; cluster = blk_queue_cluster(q); - bvprv = NULL; sg = NULL; - bio_for_each_segment(bvec, bio, i) { - __blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg, + bio_for_each_segment(bvec, bio, iter) { + __blk_segment_map_sg(q, &bvec, sglist, &bvprv, &sg, &nsegs, &cluster); } /* segments in bio */ diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 77c24ab1898a..7a06aec1dedc 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -897,15 +897,15 @@ rqbiocnt(struct request *r) static void bio_pageinc(struct bio *bio) { - struct bio_vec *bv; + struct bio_vec bv; struct page *page; - int i; + struct bvec_iter iter; - bio_for_each_segment(bv, bio, i) { + bio_for_each_segment(bv, bio, iter) { /* Non-zero page count for non-head members of * compound pages is no longer allowed by the kernel. */ - page = compound_trans_head(bv->bv_page); + page = compound_trans_head(bv.bv_page); atomic_inc(&page->_count); } } @@ -913,12 +913,12 @@ bio_pageinc(struct bio *bio) static void bio_pagedec(struct bio *bio) { - struct bio_vec *bv; struct page *page; - int i; + struct bio_vec bv; + struct bvec_iter iter; - bio_for_each_segment(bv, bio, i) { - page = compound_trans_head(bv->bv_page); + bio_for_each_segment(bv, bio, iter) { + page = compound_trans_head(bv.bv_page); atomic_dec(&page->_count); } } diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 66f5aaae15a2..e73b85cf0756 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -328,9 +328,9 @@ static void brd_make_request(struct request_queue *q, struct bio *bio) struct block_device *bdev = bio->bi_bdev; struct brd_device *brd = bdev->bd_disk->private_data; int rw; - struct bio_vec *bvec; + struct bio_vec bvec; sector_t sector; - int i; + struct bvec_iter iter; int err = -EIO; sector = bio->bi_iter.bi_sector; @@ -347,10 +347,10 @@ static void brd_make_request(struct request_queue *q, struct bio *bio) if (rw == READA) rw = READ; - bio_for_each_segment(bvec, bio, i) { - unsigned int len = bvec->bv_len; - err = brd_do_bvec(brd, bvec->bv_page, len, - bvec->bv_offset, rw, sector); + bio_for_each_segment(bvec, bio, iter) { + unsigned int len = bvec.bv_len; + err = brd_do_bvec(brd, bvec.bv_page, len, + bvec.bv_offset, rw, sector); if (err) break; sector += len >> SECTOR_SHIFT; diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 9e3818b1bc83..f4e5440aba05 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1537,15 +1537,17 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page, static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio) { - struct bio_vec *bvec; - int i; + struct bio_vec bvec; + struct bvec_iter iter; + /* hint all but last page with MSG_MORE */ - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment(bvec, bio, iter) { int err; - err = _drbd_no_send_page(mdev, bvec->bv_page, - bvec->bv_offset, bvec->bv_len, - i == bio->bi_vcnt - 1 ? 0 : MSG_MORE); + err = _drbd_no_send_page(mdev, bvec.bv_page, + bvec.bv_offset, bvec.bv_len, + bio_iter_last(bio, iter) + ? 0 : MSG_MORE); if (err) return err; } @@ -1554,15 +1556,16 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio) static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio) { - struct bio_vec *bvec; - int i; + struct bio_vec bvec; + struct bvec_iter iter; + /* hint all but last page with MSG_MORE */ - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment(bvec, bio, iter) { int err; - err = _drbd_send_page(mdev, bvec->bv_page, - bvec->bv_offset, bvec->bv_len, - i == bio->bi_vcnt - 1 ? 0 : MSG_MORE); + err = _drbd_send_page(mdev, bvec.bv_page, + bvec.bv_offset, bvec.bv_len, + bio_iter_last(bio, iter) ? 0 : MSG_MORE); if (err) return err; } diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 5326c22cdb9d..d073305ffd5e 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1595,9 +1595,10 @@ static int drbd_drain_block(struct drbd_conf *mdev, int data_size) static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, sector_t sector, int data_size) { - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; struct bio *bio; - int dgs, err, i, expect; + int dgs, err, expect; void *dig_in = mdev->tconn->int_dig_in; void *dig_vv = mdev->tconn->int_dig_vv; @@ -1617,11 +1618,11 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req, bio = req->master_bio; D_ASSERT(sector == bio->bi_iter.bi_sector); - bio_for_each_segment(bvec, bio, i) { - void *mapped = kmap(bvec->bv_page) + bvec->bv_offset; - expect = min_t(int, data_size, bvec->bv_len); + bio_for_each_segment(bvec, bio, iter) { + void *mapped = kmap(bvec.bv_page) + bvec.bv_offset; + expect = min_t(int, data_size, bvec.bv_len); err = drbd_recv_all_warn(mdev->tconn, mapped, expect); - kunmap(bvec->bv_page); + kunmap(bvec.bv_page); if (err) return err; data_size -= expect; diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 891c0ecaa292..84d3175d493a 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c @@ -313,8 +313,8 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio * { struct hash_desc desc; struct scatterlist sg; - struct bio_vec *bvec; - int i; + struct bio_vec bvec; + struct bvec_iter iter; desc.tfm = tfm; desc.flags = 0; @@ -322,8 +322,8 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio * sg_init_table(&sg, 1); crypto_hash_init(&desc); - bio_for_each_segment(bvec, bio, i) { - sg_set_page(&sg, bvec->bv_page, bvec->bv_len, bvec->bv_offset); + bio_for_each_segment(bvec, bio, iter) { + sg_set_page(&sg, bvec.bv_page, bvec.bv_len, bvec.bv_offset); crypto_hash_update(&desc, &sg, sg.length); } crypto_hash_final(&desc, digest); diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 6a86fe7b730f..6b29c4422828 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -2351,7 +2351,7 @@ static void rw_interrupt(void) /* Compute maximal contiguous buffer size. */ static int buffer_chain_size(void) { - struct bio_vec *bv; + struct bio_vec bv; int size; struct req_iterator iter; char *base; @@ -2360,10 +2360,10 @@ static int buffer_chain_size(void) size = 0; rq_for_each_segment(bv, current_req, iter) { - if (page_address(bv->bv_page) + bv->bv_offset != base + size) + if (page_address(bv.bv_page) + bv.bv_offset != base + size) break; - size += bv->bv_len; + size += bv.bv_len; } return size >> 9; @@ -2389,7 +2389,7 @@ static int transfer_size(int ssize, int max_sector, int max_size) static void copy_buffer(int ssize, int max_sector, int max_sector_2) { int remaining; /* number of transferred 512-byte sectors */ - struct bio_vec *bv; + struct bio_vec bv; char *buffer; char *dma_buffer; int size; @@ -2427,10 +2427,10 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2) if (!remaining) break; - size = bv->bv_len; + size = bv.bv_len; SUPBOUND(size, remaining); - buffer = page_address(bv->bv_page) + bv->bv_offset; + buffer = page_address(bv.bv_page) + bv.bv_offset; if (dma_buffer + size > floppy_track_buffer + (max_buffer_sectors << 10) || dma_buffer < floppy_track_buffer) { diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f5e39989adde..33fde3a39759 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -288,9 +288,10 @@ static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos) { int (*do_lo_send)(struct loop_device *, struct bio_vec *, loff_t, struct page *page); - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; struct page *page = NULL; - int i, ret = 0; + int ret = 0; if (lo->transfer != transfer_none) { page = alloc_page(GFP_NOIO | __GFP_HIGHMEM); @@ -302,11 +303,11 @@ static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos) do_lo_send = do_lo_send_direct_write; } - bio_for_each_segment(bvec, bio, i) { - ret = do_lo_send(lo, bvec, pos, page); + bio_for_each_segment(bvec, bio, iter) { + ret = do_lo_send(lo, &bvec, pos, page); if (ret < 0) break; - pos += bvec->bv_len; + pos += bvec.bv_len; } if (page) { kunmap(page); @@ -392,20 +393,20 @@ do_lo_receive(struct loop_device *lo, static int lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos) { - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; ssize_t s; - int i; - bio_for_each_segment(bvec, bio, i) { - s = do_lo_receive(lo, bvec, bsize, pos); + bio_for_each_segment(bvec, bio, iter) { + s = do_lo_receive(lo, &bvec, bsize, pos); if (s < 0) return s; - if (s != bvec->bv_len) { + if (s != bvec.bv_len) { zero_fill_bio(bio); break; } - pos += bvec->bv_len; + pos += bvec.bv_len; } return 0; } diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c index 69e9eb5a6b34..52b2f2a71470 100644 --- a/drivers/block/mtip32xx/mtip32xx.c +++ b/drivers/block/mtip32xx/mtip32xx.c @@ -3962,8 +3962,9 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) { struct driver_data *dd = queue->queuedata; struct scatterlist *sg; - struct bio_vec *bvec; - int i, nents = 0; + struct bio_vec bvec; + struct bvec_iter iter; + int nents = 0; int tag = 0, unaligned = 0; if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) { @@ -4026,11 +4027,11 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio) } /* Create the scatter list for this bio. */ - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment(bvec, bio, iter) { sg_set_page(&sg[nents], - bvec->bv_page, - bvec->bv_len, - bvec->bv_offset); + bvec.bv_page, + bvec.bv_len, + bvec.bv_offset); nents++; } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 2dc3b5153f0d..aa362f493216 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -271,7 +271,7 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req) if (nbd_cmd(req) == NBD_CMD_WRITE) { struct req_iterator iter; - struct bio_vec *bvec; + struct bio_vec bvec; /* * we are really probing at internals to determine * whether to set MSG_MORE or not... @@ -281,8 +281,8 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req) if (!rq_iter_last(req, iter)) flags = MSG_MORE; dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", - nbd->disk->disk_name, req, bvec->bv_len); - result = sock_send_bvec(nbd, bvec, flags); + nbd->disk->disk_name, req, bvec.bv_len); + result = sock_send_bvec(nbd, &bvec, flags); if (result <= 0) { dev_err(disk_to_dev(nbd->disk), "Send data failed (result %d)\n", @@ -378,10 +378,10 @@ static struct request *nbd_read_stat(struct nbd_device *nbd) nbd->disk->disk_name, req); if (nbd_cmd(req) == NBD_CMD_READ) { struct req_iterator iter; - struct bio_vec *bvec; + struct bio_vec bvec; rq_for_each_segment(bvec, req, iter) { - result = sock_recv_bvec(nbd, bvec); + result = sock_recv_bvec(nbd, &bvec); if (result <= 0) { dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n", result); @@ -389,7 +389,7 @@ static struct request *nbd_read_stat(struct nbd_device *nbd) return req; } dprintk(DBG_RX, "%s: request %p: got %d bytes data\n", - nbd->disk->disk_name, req, bvec->bv_len); + nbd->disk->disk_name, req, bvec.bv_len); } } return req; diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 53d217381873..5539d2920872 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -550,9 +550,11 @@ static int nvme_split_and_submit(struct bio *bio, struct nvme_queue *nvmeq, static int nvme_map_bio(struct nvme_queue *nvmeq, struct nvme_iod *iod, struct bio *bio, enum dma_data_direction dma_dir, int psegs) { - struct bio_vec *bvec, *bvprv = NULL; + struct bio_vec bvec, bvprv; + struct bvec_iter iter; struct scatterlist *sg = NULL; - int i, length = 0, nsegs = 0, split_len = bio->bi_iter.bi_size; + int length = 0, nsegs = 0, split_len = bio->bi_iter.bi_size; + int first = 1; if (nvmeq->dev->stripe_size) split_len = nvmeq->dev->stripe_size - @@ -560,25 +562,28 @@ static int nvme_map_bio(struct nvme_queue *nvmeq, struct nvme_iod *iod, (nvmeq->dev->stripe_size - 1)); sg_init_table(iod->sg, psegs); - bio_for_each_segment(bvec, bio, i) { - if (bvprv && BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) { - sg->length += bvec->bv_len; + bio_for_each_segment(bvec, bio, iter) { + if (!first && BIOVEC_PHYS_MERGEABLE(&bvprv, &bvec)) { + sg->length += bvec.bv_len; } else { - if (bvprv && BIOVEC_NOT_VIRT_MERGEABLE(bvprv, bvec)) - return nvme_split_and_submit(bio, nvmeq, i, - length, 0); + if (!first && BIOVEC_NOT_VIRT_MERGEABLE(&bvprv, &bvec)) + return nvme_split_and_submit(bio, nvmeq, + iter.bi_idx, + length, 0); sg = sg ? sg + 1 : iod->sg; - sg_set_page(sg, bvec->bv_page, bvec->bv_len, - bvec->bv_offset); + sg_set_page(sg, bvec.bv_page, + bvec.bv_len, bvec.bv_offset); nsegs++; } - if (split_len - length < bvec->bv_len) - return nvme_split_and_submit(bio, nvmeq, i, split_len, - split_len - length); - length += bvec->bv_len; + if (split_len - length < bvec.bv_len) + return nvme_split_and_submit(bio, nvmeq, iter.bi_idx, + split_len, + split_len - length); + length += bvec.bv_len; bvprv = bvec; + first = 0; } iod->nents = nsegs; sg_mark_end(sg); diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 464be78a0836..1c6edb9a9960 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -94,7 +94,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, { unsigned int offset = 0; struct req_iterator iter; - struct bio_vec *bvec; + struct bio_vec bvec; unsigned int i = 0; size_t size; void *buf; @@ -106,14 +106,14 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, __func__, __LINE__, i, bio_segments(iter.bio), bio_sectors(iter.bio), iter.bio->bi_iter.bi_sector); - size = bvec->bv_len; - buf = bvec_kmap_irq(bvec, &flags); + size = bvec.bv_len; + buf = bvec_kmap_irq(&bvec, &flags); if (gather) memcpy(dev->bounce_buf+offset, buf, size); else memcpy(buf, dev->bounce_buf+offset, size); offset += size; - flush_kernel_dcache_page(bvec->bv_page); + flush_kernel_dcache_page(bvec.bv_page); bvec_kunmap_irq(buf, &flags); i++; } @@ -130,7 +130,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, #ifdef DEBUG unsigned int n = 0; - struct bio_vec *bv; + struct bio_vec bv; struct req_iterator iter; rq_for_each_segment(bv, req, iter) diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 320bbfc9b902..ef45cfb98fd2 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c @@ -555,14 +555,14 @@ static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev, const char *op = write ? "write" : "read"; loff_t offset = bio->bi_iter.bi_sector << 9; int error = 0; - struct bio_vec *bvec; - unsigned int i; + struct bio_vec bvec; + struct bvec_iter iter; struct bio *next; - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment(bvec, bio, iter) { /* PS3 is ppc64, so we don't handle highmem */ - char *ptr = page_address(bvec->bv_page) + bvec->bv_offset; - size_t len = bvec->bv_len, retlen; + char *ptr = page_address(bvec.bv_page) + bvec.bv_offset; + size_t len = bvec.bv_len, retlen; dev_dbg(&dev->core, " %s %zu bytes at offset %llu\n", op, len, offset); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index a8f4fe2d4d1b..20e8ab35736b 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -1109,23 +1109,23 @@ static void bio_chain_put(struct bio *chain) */ static void zero_bio_chain(struct bio *chain, int start_ofs) { - struct bio_vec *bv; + struct bio_vec bv; + struct bvec_iter iter; unsigned long flags; void *buf; - int i; int pos = 0; while (chain) { - bio_for_each_segment(bv, chain, i) { - if (pos + bv->bv_len > start_ofs) { + bio_for_each_segment(bv, chain, iter) { + if (pos + bv.bv_len > start_ofs) { int remainder = max(start_ofs - pos, 0); - buf = bvec_kmap_irq(bv, &flags); + buf = bvec_kmap_irq(&bv, &flags); memset(buf + remainder, 0, - bv->bv_len - remainder); - flush_dcache_page(bv->bv_page); + bv.bv_len - remainder); + flush_dcache_page(bv.bv_page); bvec_kunmap_irq(buf, &flags); } - pos += bv->bv_len; + pos += bv.bv_len; } chain = chain->bi_next; @@ -1173,11 +1173,11 @@ static struct bio *bio_clone_range(struct bio *bio_src, unsigned int len, gfp_t gfpmask) { - struct bio_vec *bv; + struct bio_vec bv; + struct bvec_iter iter; + struct bvec_iter end_iter; unsigned int resid; - unsigned short idx; unsigned int voff; - unsigned short end_idx; unsigned short vcnt; struct bio *bio; @@ -1196,22 +1196,22 @@ static struct bio *bio_clone_range(struct bio *bio_src, /* Find first affected segment... */ resid = offset; - bio_for_each_segment(bv, bio_src, idx) { - if (resid < bv->bv_len) + bio_for_each_segment(bv, bio_src, iter) { + if (resid < bv.bv_len) break; - resid -= bv->bv_len; + resid -= bv.bv_len; } voff = resid; /* ...and the last affected segment */ resid += len; - __bio_for_each_segment(bv, bio_src, end_idx, idx) { - if (resid <= bv->bv_len) + __bio_for_each_segment(bv, bio_src, end_iter, iter) { + if (resid <= bv.bv_len) break; - resid -= bv->bv_len; + resid -= bv.bv_len; } - vcnt = end_idx - idx + 1; + vcnt = end_iter.bi_idx = iter.bi_idx + 1; /* Build the clone */ @@ -1229,7 +1229,7 @@ static struct bio *bio_clone_range(struct bio *bio_src, * Copy over our part of the bio_vec, then update the first * and last (or only) entries. */ - memcpy(&bio->bi_io_vec[0], &bio_src->bi_io_vec[idx], + memcpy(&bio->bi_io_vec[0], &bio_src->bi_io_vec[iter.bi_idx], vcnt * sizeof (struct bio_vec)); bio->bi_io_vec[0].bv_offset += voff; if (vcnt > 1) { diff --git a/drivers/block/rsxx/dma.c b/drivers/block/rsxx/dma.c index 3716633be3c2..cf8cd293abb5 100644 --- a/drivers/block/rsxx/dma.c +++ b/drivers/block/rsxx/dma.c @@ -684,7 +684,8 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, void *cb_data) { struct list_head dma_list[RSXX_MAX_TARGETS]; - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; unsigned long long addr8; unsigned int laddr; unsigned int bv_len; @@ -722,9 +723,9 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, bv_len -= RSXX_HW_BLK_SIZE; } } else { - bio_for_each_segment(bvec, bio, i) { - bv_len = bvec->bv_len; - bv_off = bvec->bv_offset; + bio_for_each_segment(bvec, bio, iter) { + bv_len = bvec.bv_len; + bv_off = bvec.bv_offset; while (bv_len > 0) { tgt = rsxx_get_dma_tgt(card, addr8); @@ -736,7 +737,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card, st = rsxx_queue_dma(card, &dma_list[tgt], bio_data_dir(bio), dma_off, dma_len, - laddr, bvec->bv_page, + laddr, bvec.bv_page, bv_off, cb, cb_data); if (st) goto bvec_err; diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 038a6d2aced3..b62f37925374 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -362,7 +362,7 @@ static void btree_node_write_done(struct closure *cl) struct bio_vec *bv; int n; - __bio_for_each_segment(bv, b->bio, n, 0) + bio_for_each_segment_all(bv, b->bio, n) __free_page(bv->bv_page); __btree_node_write_done(cl); @@ -421,7 +421,7 @@ static void do_btree_node_write(struct btree *b) struct bio_vec *bv; void *base = (void *) ((unsigned long) i & ~(PAGE_SIZE - 1)); - bio_for_each_segment(bv, b->bio, j) + bio_for_each_segment_all(bv, b->bio, j) memcpy(page_address(bv->bv_page), base + j * PAGE_SIZE, PAGE_SIZE); diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c index 92b3fd468a03..03cb4d114e16 100644 --- a/drivers/md/bcache/debug.c +++ b/drivers/md/bcache/debug.c @@ -173,7 +173,8 @@ void bch_data_verify(struct cached_dev *dc, struct bio *bio) { char name[BDEVNAME_SIZE]; struct bio *check; - struct bio_vec *bv; + struct bio_vec bv, *bv2; + struct bvec_iter iter; int i; check = bio_clone(bio, GFP_NOIO); @@ -185,13 +186,13 @@ void bch_data_verify(struct cached_dev *dc, struct bio *bio) submit_bio_wait(READ_SYNC, check); - bio_for_each_segment(bv, bio, i) { - void *p1 = kmap_atomic(bv->bv_page); - void *p2 = page_address(check->bi_io_vec[i].bv_page); + bio_for_each_segment(bv, bio, iter) { + void *p1 = kmap_atomic(bv.bv_page); + void *p2 = page_address(check->bi_io_vec[iter.bi_idx].bv_page); - cache_set_err_on(memcmp(p1 + bv->bv_offset, - p2 + bv->bv_offset, - bv->bv_len), + cache_set_err_on(memcmp(p1 + bv.bv_offset, + p2 + bv.bv_offset, + bv.bv_len), dc->disk.c, "verify failed at dev %s sector %llu", bdevname(dc->bdev, name), @@ -200,8 +201,8 @@ void bch_data_verify(struct cached_dev *dc, struct bio *bio) kunmap_atomic(p1); } - bio_for_each_segment_all(bv, check, i) - __free_page(bv->bv_page); + bio_for_each_segment_all(bv2, check, i) + __free_page(bv2->bv_page); out_put: bio_put(check); } diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index dc44f0689eb7..9b5b6a41a9b6 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -22,12 +22,12 @@ static void bch_bi_idx_hack_endio(struct bio *bio, int error) static void bch_generic_make_request_hack(struct bio *bio) { if (bio->bi_iter.bi_idx) { - int i; - struct bio_vec *bv; + struct bio_vec bv; + struct bvec_iter iter; struct bio *clone = bio_alloc(GFP_NOIO, bio_segments(bio)); - bio_for_each_segment(bv, bio, i) - clone->bi_io_vec[clone->bi_vcnt++] = *bv; + bio_for_each_segment(bv, bio, iter) + clone->bi_io_vec[clone->bi_vcnt++] = bv; clone->bi_iter.bi_sector = bio->bi_iter.bi_sector; clone->bi_bdev = bio->bi_bdev; @@ -73,8 +73,9 @@ static void bch_generic_make_request_hack(struct bio *bio) struct bio *bch_bio_split(struct bio *bio, int sectors, gfp_t gfp, struct bio_set *bs) { - unsigned idx = bio->bi_iter.bi_idx, vcnt = 0, nbytes = sectors << 9; - struct bio_vec *bv; + unsigned vcnt = 0, nbytes = sectors << 9; + struct bio_vec bv; + struct bvec_iter iter; struct bio *ret = NULL; BUG_ON(sectors <= 0); @@ -86,49 +87,35 @@ struct bio *bch_bio_split(struct bio *bio, int sectors, ret = bio_alloc_bioset(gfp, 1, bs); if (!ret) return NULL; - idx = 0; goto out; } - bio_for_each_segment(bv, bio, idx) { - vcnt = idx - bio->bi_iter.bi_idx; + bio_for_each_segment(bv, bio, iter) { + vcnt++; - if (!nbytes) { - ret = bio_alloc_bioset(gfp, vcnt, bs); - if (!ret) - return NULL; + if (nbytes <= bv.bv_len) + break; - memcpy(ret->bi_io_vec, __bio_iovec(bio), - sizeof(struct bio_vec) * vcnt); + nbytes -= bv.bv_len; + } - break; - } else if (nbytes < bv->bv_len) { - ret = bio_alloc_bioset(gfp, ++vcnt, bs); - if (!ret) - return NULL; + ret = bio_alloc_bioset(gfp, vcnt, bs); + if (!ret) + return NULL; - memcpy(ret->bi_io_vec, __bio_iovec(bio), - sizeof(struct bio_vec) * vcnt); + bio_for_each_segment(bv, bio, iter) { + ret->bi_io_vec[ret->bi_vcnt++] = bv; - ret->bi_io_vec[vcnt - 1].bv_len = nbytes; - bv->bv_offset += nbytes; - bv->bv_len -= nbytes; + if (ret->bi_vcnt == vcnt) break; - } - - nbytes -= bv->bv_len; } + + ret->bi_io_vec[ret->bi_vcnt - 1].bv_len = nbytes; out: ret->bi_bdev = bio->bi_bdev; ret->bi_iter.bi_sector = bio->bi_iter.bi_sector; ret->bi_iter.bi_size = sectors << 9; ret->bi_rw = bio->bi_rw; - ret->bi_vcnt = vcnt; - ret->bi_max_vecs = vcnt; - - bio->bi_iter.bi_sector += sectors; - bio->bi_iter.bi_size -= sectors << 9; - bio->bi_iter.bi_idx = idx; if (bio_integrity(bio)) { if (bio_integrity_clone(ret, bio, gfp)) { @@ -137,9 +124,10 @@ out: } bio_integrity_trim(ret, 0, bio_sectors(ret)); - bio_integrity_trim(bio, bio_sectors(ret), bio_sectors(bio)); } + bio_advance(bio, ret->bi_iter.bi_size); + return ret; } @@ -155,12 +143,13 @@ static unsigned bch_bio_max_sectors(struct bio *bio) if (bio_segments(bio) > max_segments || q->merge_bvec_fn) { - struct bio_vec *bv; - int i, seg = 0; + struct bio_vec bv; + struct bvec_iter iter; + unsigned seg = 0; ret = 0; - bio_for_each_segment(bv, bio, i) { + bio_for_each_segment(bv, bio, iter) { struct bvec_merge_data bvm = { .bi_bdev = bio->bi_bdev, .bi_sector = bio->bi_iter.bi_sector, @@ -172,11 +161,11 @@ static unsigned bch_bio_max_sectors(struct bio *bio) break; if (q->merge_bvec_fn && - q->merge_bvec_fn(q, &bvm, bv) < (int) bv->bv_len) + q->merge_bvec_fn(q, &bvm, &bv) < (int) bv.bv_len) break; seg++; - ret += bv->bv_len >> 9; + ret += bv.bv_len >> 9; } } diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 47a9bbc75124..4c0a422fd49f 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -198,14 +198,14 @@ static bool verify(struct cached_dev *dc, struct bio *bio) static void bio_csum(struct bio *bio, struct bkey *k) { - struct bio_vec *bv; + struct bio_vec bv; + struct bvec_iter iter; uint64_t csum = 0; - int i; - bio_for_each_segment(bv, bio, i) { - void *d = kmap(bv->bv_page) + bv->bv_offset; - csum = bch_crc64_update(csum, d, bv->bv_len); - kunmap(bv->bv_page); + bio_for_each_segment(bv, bio, iter) { + void *d = kmap(bv.bv_page) + bv.bv_offset; + csum = bch_crc64_update(csum, d, bv.bv_len); + kunmap(bv.bv_page); } k->ptr[KEY_PTRS(k)] = csum & (~0ULL >> 1); @@ -1182,17 +1182,17 @@ void bch_cached_dev_request_init(struct cached_dev *dc) static int flash_dev_cache_miss(struct btree *b, struct search *s, struct bio *bio, unsigned sectors) { - struct bio_vec *bv; - int i; + struct bio_vec bv; + struct bvec_iter iter; /* Zero fill bio */ - bio_for_each_segment(bv, bio, i) { - unsigned j = min(bv->bv_len >> 9, sectors); + bio_for_each_segment(bv, bio, iter) { + unsigned j = min(bv.bv_len >> 9, sectors); - void *p = kmap(bv->bv_page); - memset(p + bv->bv_offset, 0, j << 9); - kunmap(bv->bv_page); + void *p = kmap(bv.bv_page); + memset(p + bv.bv_offset, 0, j << 9); + kunmap(bv.bv_page); sectors -= j; } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a5d9c0ee4d60..bef353c51c04 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -937,9 +937,9 @@ static struct dma_async_tx_descriptor * async_copy_data(int frombio, struct bio *bio, struct page *page, sector_t sector, struct dma_async_tx_descriptor *tx) { - struct bio_vec *bvl; + struct bio_vec bvl; + struct bvec_iter iter; struct page *bio_page; - int i; int page_offset; struct async_submit_ctl submit; enum async_tx_flags flags = 0; @@ -953,8 +953,8 @@ async_copy_data(int frombio, struct bio *bio, struct page *page, flags |= ASYNC_TX_FENCE; init_async_submit(&submit, flags, tx, NULL, NULL, NULL); - bio_for_each_segment(bvl, bio, i) { - int len = bvl->bv_len; + bio_for_each_segment(bvl, bio, iter) { + int len = bvl.bv_len; int clen; int b_offset = 0; @@ -970,8 +970,8 @@ async_copy_data(int frombio, struct bio *bio, struct page *page, clen = len; if (clen > 0) { - b_offset += bvl->bv_offset; - bio_page = bvl->bv_page; + b_offset += bvl.bv_offset; + bio_page = bvl.bv_page; if (frombio) tx = async_memcpy(page, bio_page, page_offset, b_offset, clen, &submit); diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 92bd22ce6760..9cbc567698ce 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -504,7 +504,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, struct dasd_diag_req *dreq; struct dasd_diag_bio *dbio; struct req_iterator iter; - struct bio_vec *bv; + struct bio_vec bv; char *dst; unsigned int count, datasize; sector_t recid, first_rec, last_rec; @@ -525,10 +525,10 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, /* Check struct bio and count the number of blocks for the request. */ count = 0; rq_for_each_segment(bv, req, iter) { - if (bv->bv_len & (blksize - 1)) + if (bv.bv_len & (blksize - 1)) /* Fba can only do full blocks. */ return ERR_PTR(-EINVAL); - count += bv->bv_len >> (block->s2b_shift + 9); + count += bv.bv_len >> (block->s2b_shift + 9); } /* Paranoia. */ if (count != last_rec - first_rec + 1) @@ -545,8 +545,8 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, dbio = dreq->bio; recid = first_rec; rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; - for (off = 0; off < bv->bv_len; off += blksize) { + dst = page_address(bv.bv_page) + bv.bv_offset; + for (off = 0; off < bv.bv_len; off += blksize) { memset(dbio, 0, sizeof (struct dasd_diag_bio)); dbio->type = rw_cmd; dbio->block_number = recid + 1; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index cee7e2708a1f..70d177017329 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -2551,7 +2551,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( struct dasd_ccw_req *cqr; struct ccw1 *ccw; struct req_iterator iter; - struct bio_vec *bv; + struct bio_vec bv; char *dst; unsigned int off; int count, cidaw, cplength, datasize; @@ -2573,13 +2573,13 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( count = 0; cidaw = 0; rq_for_each_segment(bv, req, iter) { - if (bv->bv_len & (blksize - 1)) + if (bv.bv_len & (blksize - 1)) /* Eckd can only do full blocks. */ return ERR_PTR(-EINVAL); - count += bv->bv_len >> (block->s2b_shift + 9); + count += bv.bv_len >> (block->s2b_shift + 9); #if defined(CONFIG_64BIT) - if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) - cidaw += bv->bv_len >> (block->s2b_shift + 9); + if (idal_is_needed (page_address(bv.bv_page), bv.bv_len)) + cidaw += bv.bv_len >> (block->s2b_shift + 9); #endif } /* Paranoia. */ @@ -2650,16 +2650,16 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single( last_rec - recid + 1, cmd, basedev, blksize); } rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; + dst = page_address(bv.bv_page) + bv.bv_offset; if (dasd_page_cache) { char *copy = kmem_cache_alloc(dasd_page_cache, GFP_DMA | __GFP_NOWARN); if (copy && rq_data_dir(req) == WRITE) - memcpy(copy + bv->bv_offset, dst, bv->bv_len); + memcpy(copy + bv.bv_offset, dst, bv.bv_len); if (copy) - dst = copy + bv->bv_offset; + dst = copy + bv.bv_offset; } - for (off = 0; off < bv->bv_len; off += blksize) { + for (off = 0; off < bv.bv_len; off += blksize) { sector_t trkid = recid; unsigned int recoffs = sector_div(trkid, blk_per_trk); rcmd = cmd; @@ -2735,7 +2735,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( struct dasd_ccw_req *cqr; struct ccw1 *ccw; struct req_iterator iter; - struct bio_vec *bv; + struct bio_vec bv; char *dst, *idaw_dst; unsigned int cidaw, cplength, datasize; unsigned int tlf; @@ -2813,8 +2813,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track( idaw_dst = NULL; idaw_len = 0; rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; - seg_len = bv->bv_len; + dst = page_address(bv.bv_page) + bv.bv_offset; + seg_len = bv.bv_len; while (seg_len) { if (new_track) { trkid = recid; @@ -3039,7 +3039,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( { struct dasd_ccw_req *cqr; struct req_iterator iter; - struct bio_vec *bv; + struct bio_vec bv; char *dst; unsigned int trkcount, ctidaw; unsigned char cmd; @@ -3125,8 +3125,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( new_track = 1; recid = first_rec; rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; - seg_len = bv->bv_len; + dst = page_address(bv.bv_page) + bv.bv_offset; + seg_len = bv.bv_len; while (seg_len) { if (new_track) { trkid = recid; @@ -3158,9 +3158,9 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track( } } else { rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; + dst = page_address(bv.bv_page) + bv.bv_offset; last_tidaw = itcw_add_tidaw(itcw, 0x00, - dst, bv->bv_len); + dst, bv.bv_len); if (IS_ERR(last_tidaw)) { ret = -EINVAL; goto out_error; @@ -3276,7 +3276,7 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, struct dasd_ccw_req *cqr; struct ccw1 *ccw; struct req_iterator iter; - struct bio_vec *bv; + struct bio_vec bv; char *dst; unsigned char cmd; unsigned int trkcount; @@ -3376,8 +3376,8 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev, idaws = idal_create_words(idaws, rawpadpage, PAGE_SIZE); } rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; - seg_len = bv->bv_len; + dst = page_address(bv.bv_page) + bv.bv_offset; + seg_len = bv.bv_len; if (cmd == DASD_ECKD_CCW_READ_TRACK) memset(dst, 0, seg_len); if (!len_to_track_end) { @@ -3422,7 +3422,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) struct dasd_eckd_private *private; struct ccw1 *ccw; struct req_iterator iter; - struct bio_vec *bv; + struct bio_vec bv; char *dst, *cda; unsigned int blksize, blk_per_trk, off; sector_t recid; @@ -3440,8 +3440,8 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) if (private->uses_cdl == 0 || recid > 2*blk_per_trk) ccw++; rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; - for (off = 0; off < bv->bv_len; off += blksize) { + dst = page_address(bv.bv_page) + bv.bv_offset; + for (off = 0; off < bv.bv_len; off += blksize) { /* Skip locate record. */ if (private->uses_cdl && recid <= 2*blk_per_trk) ccw++; @@ -3452,7 +3452,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req) cda = (char *)((addr_t) ccw->cda); if (dst != cda) { if (rq_data_dir(req) == READ) - memcpy(dst, cda, bv->bv_len); + memcpy(dst, cda, bv.bv_len); kmem_cache_free(dasd_page_cache, (void *)((addr_t)cda & PAGE_MASK)); } diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 9cbc8c32ba59..2c8e68bf9a1c 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -260,7 +260,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, struct dasd_ccw_req *cqr; struct ccw1 *ccw; struct req_iterator iter; - struct bio_vec *bv; + struct bio_vec bv; char *dst; int count, cidaw, cplength, datasize; sector_t recid, first_rec, last_rec; @@ -283,13 +283,13 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, count = 0; cidaw = 0; rq_for_each_segment(bv, req, iter) { - if (bv->bv_len & (blksize - 1)) + if (bv.bv_len & (blksize - 1)) /* Fba can only do full blocks. */ return ERR_PTR(-EINVAL); - count += bv->bv_len >> (block->s2b_shift + 9); + count += bv.bv_len >> (block->s2b_shift + 9); #if defined(CONFIG_64BIT) - if (idal_is_needed (page_address(bv->bv_page), bv->bv_len)) - cidaw += bv->bv_len / blksize; + if (idal_is_needed (page_address(bv.bv_page), bv.bv_len)) + cidaw += bv.bv_len / blksize; #endif } /* Paranoia. */ @@ -326,16 +326,16 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, } recid = first_rec; rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; + dst = page_address(bv.bv_page) + bv.bv_offset; if (dasd_page_cache) { char *copy = kmem_cache_alloc(dasd_page_cache, GFP_DMA | __GFP_NOWARN); if (copy && rq_data_dir(req) == WRITE) - memcpy(copy + bv->bv_offset, dst, bv->bv_len); + memcpy(copy + bv.bv_offset, dst, bv.bv_len); if (copy) - dst = copy + bv->bv_offset; + dst = copy + bv.bv_offset; } - for (off = 0; off < bv->bv_len; off += blksize) { + for (off = 0; off < bv.bv_len; off += blksize) { /* Locate record for stupid devices. */ if (private->rdc_data.mode.bits.data_chain == 0) { ccw[-1].flags |= CCW_FLAG_CC; @@ -384,7 +384,7 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) struct dasd_fba_private *private; struct ccw1 *ccw; struct req_iterator iter; - struct bio_vec *bv; + struct bio_vec bv; char *dst, *cda; unsigned int blksize, off; int status; @@ -399,8 +399,8 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) if (private->rdc_data.mode.bits.data_chain != 0) ccw++; rq_for_each_segment(bv, req, iter) { - dst = page_address(bv->bv_page) + bv->bv_offset; - for (off = 0; off < bv->bv_len; off += blksize) { + dst = page_address(bv.bv_page) + bv.bv_offset; + for (off = 0; off < bv.bv_len; off += blksize) { /* Skip locate record. */ if (private->rdc_data.mode.bits.data_chain == 0) ccw++; @@ -411,7 +411,7 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req) cda = (char *)((addr_t) ccw->cda); if (dst != cda) { if (rq_data_dir(req) == READ) - memcpy(dst, cda, bv->bv_len); + memcpy(dst, cda, bv.bv_len); kmem_cache_free(dasd_page_cache, (void *)((addr_t)cda & PAGE_MASK)); } diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 16814a8457f8..ebf41e228e55 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -808,12 +808,12 @@ static void dcssblk_make_request(struct request_queue *q, struct bio *bio) { struct dcssblk_dev_info *dev_info; - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; unsigned long index; unsigned long page_addr; unsigned long source_addr; unsigned long bytes_done; - int i; bytes_done = 0; dev_info = bio->bi_bdev->bd_disk->private_data; @@ -844,21 +844,21 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) } index = (bio->bi_iter.bi_sector >> 3); - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment(bvec, bio, iter) { page_addr = (unsigned long) - page_address(bvec->bv_page) + bvec->bv_offset; + page_address(bvec.bv_page) + bvec.bv_offset; source_addr = dev_info->start + (index<<12) + bytes_done; - if (unlikely((page_addr & 4095) != 0) || (bvec->bv_len & 4095) != 0) + if (unlikely((page_addr & 4095) != 0) || (bvec.bv_len & 4095) != 0) // More paranoia. goto fail; if (bio_data_dir(bio) == READ) { memcpy((void*)page_addr, (void*)source_addr, - bvec->bv_len); + bvec.bv_len); } else { memcpy((void*)source_addr, (void*)page_addr, - bvec->bv_len); + bvec.bv_len); } - bytes_done += bvec->bv_len; + bytes_done += bvec.bv_len; } bio_endio(bio, 0); return; diff --git a/drivers/s390/block/scm_blk.c b/drivers/s390/block/scm_blk.c index d0ab5019d885..76bed1743db1 100644 --- a/drivers/s390/block/scm_blk.c +++ b/drivers/s390/block/scm_blk.c @@ -130,7 +130,7 @@ static void scm_request_prepare(struct scm_request *scmrq) struct aidaw *aidaw = scmrq->aidaw; struct msb *msb = &scmrq->aob->msb[0]; struct req_iterator iter; - struct bio_vec *bv; + struct bio_vec bv; msb->bs = MSB_BS_4K; scmrq->aob->request.msb_count = 1; @@ -142,9 +142,9 @@ static void scm_request_prepare(struct scm_request *scmrq) msb->data_addr = (u64) aidaw; rq_for_each_segment(bv, scmrq->request, iter) { - WARN_ON(bv->bv_offset); - msb->blk_count += bv->bv_len >> 12; - aidaw->data_addr = (u64) page_address(bv->bv_page); + WARN_ON(bv.bv_offset); + msb->blk_count += bv.bv_len >> 12; + aidaw->data_addr = (u64) page_address(bv.bv_page); aidaw++; } } diff --git a/drivers/s390/block/scm_blk_cluster.c b/drivers/s390/block/scm_blk_cluster.c index 27f930cd657f..9aae909d47a5 100644 --- a/drivers/s390/block/scm_blk_cluster.c +++ b/drivers/s390/block/scm_blk_cluster.c @@ -122,7 +122,7 @@ static void scm_prepare_cluster_request(struct scm_request *scmrq) struct aidaw *aidaw = scmrq->aidaw; struct msb *msb = &scmrq->aob->msb[0]; struct req_iterator iter; - struct bio_vec *bv; + struct bio_vec bv; int i = 0; u64 addr; @@ -163,7 +163,7 @@ static void scm_prepare_cluster_request(struct scm_request *scmrq) i++; } rq_for_each_segment(bv, req, iter) { - aidaw->data_addr = (u64) page_address(bv->bv_page); + aidaw->data_addr = (u64) page_address(bv.bv_page); aidaw++; i++; } diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index dd4e73fdb323..3e530f9da8c4 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -184,11 +184,11 @@ static unsigned long xpram_highest_page_index(void) static void xpram_make_request(struct request_queue *q, struct bio *bio) { xpram_device_t *xdev = bio->bi_bdev->bd_disk->private_data; - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; unsigned int index; unsigned long page_addr; unsigned long bytes; - int i; if ((bio->bi_iter.bi_sector & 7) != 0 || (bio->bi_iter.bi_size & 4095) != 0) @@ -200,10 +200,10 @@ static void xpram_make_request(struct request_queue *q, struct bio *bio) if ((bio->bi_iter.bi_sector >> 3) > 0xffffffffU - xdev->offset) goto fail; index = (bio->bi_iter.bi_sector >> 3) + xdev->offset; - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment(bvec, bio, iter) { page_addr = (unsigned long) - kmap(bvec->bv_page) + bvec->bv_offset; - bytes = bvec->bv_len; + kmap(bvec.bv_page) + bvec.bv_offset; + bytes = bvec.bv_len; if ((page_addr & 4095) != 0 || (bytes & 4095) != 0) /* More paranoia. */ goto fail; diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 9d26637308be..7143e86af326 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -1901,7 +1901,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); Mpi2SmpPassthroughRequest_t *mpi_request; Mpi2SmpPassthroughReply_t *mpi_reply; - int rc, i; + int rc; u16 smid; u32 ioc_state; unsigned long timeleft; @@ -1916,7 +1916,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, void *pci_addr_out = NULL; u16 wait_state_count; struct request *rsp = req->next_rq; - struct bio_vec *bvec = NULL; + struct bio_vec bvec; + struct bvec_iter iter; if (!rsp) { printk(MPT2SAS_ERR_FMT "%s: the smp response space is " @@ -1955,11 +1956,11 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, goto out; } - bio_for_each_segment(bvec, req->bio, i) { + bio_for_each_segment(bvec, req->bio, iter) { memcpy(pci_addr_out + offset, - page_address(bvec->bv_page) + bvec->bv_offset, - bvec->bv_len); - offset += bvec->bv_len; + page_address(bvec.bv_page) + bvec.bv_offset, + bvec.bv_len); + offset += bvec.bv_len; } } else { dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), @@ -2106,19 +2107,19 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, u32 offset = 0; u32 bytes_to_copy = le16_to_cpu(mpi_reply->ResponseDataLength); - bio_for_each_segment(bvec, rsp->bio, i) { - if (bytes_to_copy <= bvec->bv_len) { - memcpy(page_address(bvec->bv_page) + - bvec->bv_offset, pci_addr_in + + bio_for_each_segment(bvec, rsp->bio, iter) { + if (bytes_to_copy <= bvec.bv_len) { + memcpy(page_address(bvec.bv_page) + + bvec.bv_offset, pci_addr_in + offset, bytes_to_copy); break; } else { - memcpy(page_address(bvec->bv_page) + - bvec->bv_offset, pci_addr_in + - offset, bvec->bv_len); - bytes_to_copy -= bvec->bv_len; + memcpy(page_address(bvec.bv_page) + + bvec.bv_offset, pci_addr_in + + offset, bvec.bv_len); + bytes_to_copy -= bvec.bv_len; } - offset += bvec->bv_len; + offset += bvec.bv_len; } } } else { diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index e771a88c6a74..196a67f2e95f 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -1884,7 +1884,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, struct MPT3SAS_ADAPTER *ioc = shost_priv(shost); Mpi2SmpPassthroughRequest_t *mpi_request; Mpi2SmpPassthroughReply_t *mpi_reply; - int rc, i; + int rc; u16 smid; u32 ioc_state; unsigned long timeleft; @@ -1898,7 +1898,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, void *pci_addr_out = NULL; u16 wait_state_count; struct request *rsp = req->next_rq; - struct bio_vec *bvec = NULL; + struct bio_vec bvec; + struct bvec_iter iter; if (!rsp) { pr_err(MPT3SAS_FMT "%s: the smp response space is missing\n", @@ -1938,11 +1939,11 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, goto out; } - bio_for_each_segment(bvec, req->bio, i) { + bio_for_each_segment(bvec, req->bio, iter) { memcpy(pci_addr_out + offset, - page_address(bvec->bv_page) + bvec->bv_offset, - bvec->bv_len); - offset += bvec->bv_len; + page_address(bvec.bv_page) + bvec.bv_offset, + bvec.bv_len); + offset += bvec.bv_len; } } else { dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), @@ -2067,19 +2068,19 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, u32 offset = 0; u32 bytes_to_copy = le16_to_cpu(mpi_reply->ResponseDataLength); - bio_for_each_segment(bvec, rsp->bio, i) { - if (bytes_to_copy <= bvec->bv_len) { - memcpy(page_address(bvec->bv_page) + - bvec->bv_offset, pci_addr_in + + bio_for_each_segment(bvec, rsp->bio, iter) { + if (bytes_to_copy <= bvec.bv_len) { + memcpy(page_address(bvec.bv_page) + + bvec.bv_offset, pci_addr_in + offset, bytes_to_copy); break; } else { - memcpy(page_address(bvec->bv_page) + - bvec->bv_offset, pci_addr_in + - offset, bvec->bv_len); - bytes_to_copy -= bvec->bv_len; + memcpy(page_address(bvec.bv_page) + + bvec.bv_offset, pci_addr_in + + offset, bvec.bv_len); + bytes_to_copy -= bvec.bv_len; } - offset += bvec->bv_len; + offset += bvec.bv_len; } } } else { diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c index 53741be754b4..581ff78be1a2 100644 --- a/drivers/staging/lustre/lustre/llite/lloop.c +++ b/drivers/staging/lustre/lustre/llite/lloop.c @@ -194,10 +194,10 @@ static int do_bio_lustrebacked(struct lloop_device *lo, struct bio *head) struct cl_object *obj = ll_i2info(inode)->lli_clob; pgoff_t offset; int ret; - int i; int rw; obd_count page_count = 0; - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; struct bio *bio; ssize_t bytes; @@ -221,14 +221,14 @@ static int do_bio_lustrebacked(struct lloop_device *lo, struct bio *head) LASSERT(rw == bio->bi_rw); offset = (pgoff_t)(bio->bi_iter.bi_sector << 9) + lo->lo_offset; - bio_for_each_segment(bvec, bio, i) { - BUG_ON(bvec->bv_offset != 0); - BUG_ON(bvec->bv_len != PAGE_CACHE_SIZE); + bio_for_each_segment(bvec, bio, iter) { + BUG_ON(bvec.bv_offset != 0); + BUG_ON(bvec.bv_len != PAGE_CACHE_SIZE); - pages[page_count] = bvec->bv_page; + pages[page_count] = bvec.bv_page; offsets[page_count] = offset; page_count++; - offset += bvec->bv_len; + offset += bvec.bv_len; } LASSERT(page_count <= LLOOP_MAX_SEGMENTS); } diff --git a/drivers/staging/zram/zram_drv.c b/drivers/staging/zram/zram_drv.c index e9e6f984092b..6f988382b174 100644 --- a/drivers/staging/zram/zram_drv.c +++ b/drivers/staging/zram/zram_drv.c @@ -672,9 +672,10 @@ static ssize_t reset_store(struct device *dev, static void __zram_make_request(struct zram *zram, struct bio *bio, int rw) { - int i, offset; + int offset; u32 index; - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; switch (rw) { case READ: @@ -689,33 +690,33 @@ static void __zram_make_request(struct zram *zram, struct bio *bio, int rw) offset = (bio->bi_iter.bi_sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT; - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment(bvec, bio, iter) { int max_transfer_size = PAGE_SIZE - offset; - if (bvec->bv_len > max_transfer_size) { + if (bvec.bv_len > max_transfer_size) { /* * zram_bvec_rw() can only make operation on a single * zram page. Split the bio vector. */ struct bio_vec bv; - bv.bv_page = bvec->bv_page; + bv.bv_page = bvec.bv_page; bv.bv_len = max_transfer_size; - bv.bv_offset = bvec->bv_offset; + bv.bv_offset = bvec.bv_offset; if (zram_bvec_rw(zram, &bv, index, offset, bio, rw) < 0) goto out; - bv.bv_len = bvec->bv_len - max_transfer_size; + bv.bv_len = bvec.bv_len - max_transfer_size; bv.bv_offset += max_transfer_size; if (zram_bvec_rw(zram, &bv, index+1, 0, bio, rw) < 0) goto out; } else - if (zram_bvec_rw(zram, bvec, index, offset, bio, rw) + if (zram_bvec_rw(zram, &bvec, index, offset, bio, rw) < 0) goto out; - update_position(&index, &offset, bvec); + update_position(&index, &offset, &bvec); } set_bit(BIO_UPTODATE, &bio->bi_flags); diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index 08e3d1388c65..9127db86f315 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c @@ -299,25 +299,26 @@ static void bio_integrity_generate(struct bio *bio) { struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); struct blk_integrity_exchg bix; - struct bio_vec *bv; + struct bio_vec bv; + struct bvec_iter iter; sector_t sector = bio->bi_iter.bi_sector; - unsigned int i, sectors, total; + unsigned int sectors, total; void *prot_buf = bio->bi_integrity->bip_buf; total = 0; bix.disk_name = bio->bi_bdev->bd_disk->disk_name; bix.sector_size = bi->sector_size; - bio_for_each_segment(bv, bio, i) { - void *kaddr = kmap_atomic(bv->bv_page); - bix.data_buf = kaddr + bv->bv_offset; - bix.data_size = bv->bv_len; + bio_for_each_segment(bv, bio, iter) { + void *kaddr = kmap_atomic(bv.bv_page); + bix.data_buf = kaddr + bv.bv_offset; + bix.data_size = bv.bv_len; bix.prot_buf = prot_buf; bix.sector = sector; bi->generate_fn(&bix); - sectors = bv->bv_len / bi->sector_size; + sectors = bv.bv_len / bi->sector_size; sector += sectors; prot_buf += sectors * bi->tuple_size; total += sectors * bi->tuple_size; @@ -441,19 +442,20 @@ static int bio_integrity_verify(struct bio *bio) { struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); struct blk_integrity_exchg bix; - struct bio_vec *bv; + struct bio_vec bv; + struct bvec_iter iter; sector_t sector = bio->bi_integrity->bip_sector; - unsigned int i, sectors, total, ret; + unsigned int sectors, total, ret; void *prot_buf = bio->bi_integrity->bip_buf; ret = total = 0; bix.disk_name = bio->bi_bdev->bd_disk->disk_name; bix.sector_size = bi->sector_size; - bio_for_each_segment(bv, bio, i) { - void *kaddr = kmap_atomic(bv->bv_page); - bix.data_buf = kaddr + bv->bv_offset; - bix.data_size = bv->bv_len; + bio_for_each_segment(bv, bio, iter) { + void *kaddr = kmap_atomic(bv.bv_page); + bix.data_buf = kaddr + bv.bv_offset; + bix.data_size = bv.bv_len; bix.prot_buf = prot_buf; bix.sector = sector; @@ -464,7 +466,7 @@ static int bio_integrity_verify(struct bio *bio) return ret; } - sectors = bv->bv_len / bi->sector_size; + sectors = bv.bv_len / bi->sector_size; sector += sectors; prot_buf += sectors * bi->tuple_size; total += sectors * bi->tuple_size; diff --git a/fs/bio.c b/fs/bio.c index 7bb281fc3d5c..8b7f14a95503 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -473,13 +473,13 @@ EXPORT_SYMBOL(bio_alloc_bioset); void zero_fill_bio(struct bio *bio) { unsigned long flags; - struct bio_vec *bv; - int i; + struct bio_vec bv; + struct bvec_iter iter; - bio_for_each_segment(bv, bio, i) { - char *data = bvec_kmap_irq(bv, &flags); - memset(data, 0, bv->bv_len); - flush_dcache_page(bv->bv_page); + bio_for_each_segment(bv, bio, iter) { + char *data = bvec_kmap_irq(&bv, &flags); + memset(data, 0, bv.bv_len); + flush_dcache_page(bv.bv_page); bvec_kunmap_irq(data, &flags); } } @@ -1687,11 +1687,11 @@ void bio_check_pages_dirty(struct bio *bio) #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE void bio_flush_dcache_pages(struct bio *bi) { - int i; - struct bio_vec *bvec; + struct bio_vec bvec; + struct bvec_iter iter; - bio_for_each_segment(bvec, bi, i) - flush_dcache_page(bvec->bv_page); + bio_for_each_segment(bvec, bi, iter) + flush_dcache_page(bvec.bv_page); } EXPORT_SYMBOL(bio_flush_dcache_pages); #endif @@ -1840,7 +1840,7 @@ void bio_trim(struct bio *bio, int offset, int size) bio->bi_iter.bi_idx = 0; } /* Make sure vcnt and last bv are not too big */ - bio_for_each_segment(bvec, bio, i) { + bio_for_each_segment_all(bvec, bio, i) { if (sofar + bvec->bv_len > size) bvec->bv_len = size - sofar; if (bvec->bv_len == 0) { diff --git a/include/linux/bio.h b/include/linux/bio.h index 9f182fcbe714..c16adb5f69f8 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -63,10 +63,13 @@ */ #define bio_iovec_idx(bio, idx) (&((bio)->bi_io_vec[(idx)])) #define __bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) -#define bio_iovec(bio) (*__bio_iovec(bio)) + +#define bio_iter_iovec(bio, iter) ((bio)->bi_io_vec[(iter).bi_idx]) #define bio_page(bio) (bio_iovec((bio)).bv_page) #define bio_offset(bio) (bio_iovec((bio)).bv_offset) +#define bio_iovec(bio) (*__bio_iovec(bio)) + #define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_iter.bi_idx) #define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) #define bio_end_sector(bio) ((bio)->bi_iter.bi_sector + bio_sectors((bio))) @@ -133,15 +136,6 @@ static inline void *bio_data(struct bio *bio) #define bio_io_error(bio) bio_endio((bio), -EIO) -/* - * drivers should not use the __ version unless they _really_ know what - * they're doing - */ -#define __bio_for_each_segment(bvl, bio, i, start_idx) \ - for (bvl = bio_iovec_idx((bio), (start_idx)), i = (start_idx); \ - i < (bio)->bi_vcnt; \ - bvl++, i++) - /* * drivers should _never_ use the all version - the bio may have been split * before it got to the driver and the driver won't own all of it @@ -151,10 +145,16 @@ static inline void *bio_data(struct bio *bio) bvl = bio_iovec_idx((bio), (i)), i < (bio)->bi_vcnt; \ i++) -#define bio_for_each_segment(bvl, bio, i) \ - for (i = (bio)->bi_iter.bi_idx; \ - bvl = bio_iovec_idx((bio), (i)), i < (bio)->bi_vcnt; \ - i++) +#define __bio_for_each_segment(bvl, bio, iter, start) \ + for (iter = (start); \ + bvl = bio_iter_iovec((bio), (iter)), \ + (iter).bi_idx < (bio)->bi_vcnt; \ + (iter).bi_idx++) + +#define bio_for_each_segment(bvl, bio, iter) \ + __bio_for_each_segment(bvl, bio, iter, (bio)->bi_iter) + +#define bio_iter_last(bio, iter) ((iter).bi_idx == (bio)->bi_vcnt - 1) /* * get a reference to a bio, so it won't disappear. the intended use is diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 1b135d49b279..337b92a54658 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -735,7 +735,7 @@ struct rq_map_data { }; struct req_iterator { - int i; + struct bvec_iter iter; struct bio *bio; }; @@ -748,10 +748,11 @@ struct req_iterator { #define rq_for_each_segment(bvl, _rq, _iter) \ __rq_for_each_bio(_iter.bio, _rq) \ - bio_for_each_segment(bvl, _iter.bio, _iter.i) + bio_for_each_segment(bvl, _iter.bio, _iter.iter) #define rq_iter_last(rq, _iter) \ - (_iter.bio->bi_next == NULL && _iter.i == _iter.bio->bi_vcnt-1) + (_iter.bio->bi_next == NULL && \ + bio_iter_last(_iter.bio, _iter.iter)) #ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE # error "You should define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform" diff --git a/mm/bounce.c b/mm/bounce.c index 5a7d58fb883b..523918b8c6dc 100644 --- a/mm/bounce.c +++ b/mm/bounce.c @@ -98,27 +98,24 @@ int init_emergency_isa_pool(void) static void copy_to_high_bio_irq(struct bio *to, struct bio *from) { unsigned char *vfrom; - struct bio_vec *tovec, *fromvec; - int i; - - bio_for_each_segment(tovec, to, i) { - fromvec = from->bi_io_vec + i; - - /* - * not bounced - */ - if (tovec->bv_page == fromvec->bv_page) - continue; - - /* - * fromvec->bv_offset and fromvec->bv_len might have been - * modified by the block layer, so use the original copy, - * bounce_copy_vec already uses tovec->bv_len - */ - vfrom = page_address(fromvec->bv_page) + tovec->bv_offset; + struct bio_vec tovec, *fromvec = from->bi_io_vec; + struct bvec_iter iter; + + bio_for_each_segment(tovec, to, iter) { + if (tovec.bv_page != fromvec->bv_page) { + /* + * fromvec->bv_offset and fromvec->bv_len might have + * been modified by the block layer, so use the original + * copy, bounce_copy_vec already uses tovec->bv_len + */ + vfrom = page_address(fromvec->bv_page) + + tovec.bv_offset; + + bounce_copy_vec(&tovec, vfrom); + flush_dcache_page(tovec.bv_page); + } - bounce_copy_vec(tovec, vfrom); - flush_dcache_page(tovec->bv_page); + fromvec++; } } @@ -201,13 +198,14 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, { struct bio *bio; int rw = bio_data_dir(*bio_orig); - struct bio_vec *to, *from; + struct bio_vec *to, from; + struct bvec_iter iter; unsigned i; if (force) goto bounce; - bio_for_each_segment(from, *bio_orig, i) - if (page_to_pfn(from->bv_page) > queue_bounce_pfn(q)) + bio_for_each_segment(from, *bio_orig, iter) + if (page_to_pfn(from.bv_page) > queue_bounce_pfn(q)) goto bounce; return; -- cgit v1.2.3-59-g8ed1b From 4550dd6c6b062fc5e5b647296d55da22616123c3 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Wed, 7 Aug 2013 14:26:21 -0700 Subject: block: Immutable bio vecs This adds a mechanism by which we can advance a bio by an arbitrary number of bytes without modifying the biovec: bio->bi_iter.bi_bvec_done indicates the number of bytes completed in the current bvec. Various driver code still needs to be updated to not refer to the bvec directly before we can use this for interesting things, like efficient bio splitting. Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: Lars Ellenberg Cc: Paul Clements Cc: drbd-user@lists.linbit.com Cc: nbd-general@lists.sourceforge.net --- Documentation/block/biovecs.txt | 111 ++++++++++++++++++++++++++++++++++++++++ drivers/block/drbd/drbd_main.c | 4 +- drivers/block/nbd.c | 2 +- fs/bio.c | 27 +--------- include/linux/bio.h | 81 ++++++++++++++++++++++++++--- include/linux/blk_types.h | 3 ++ include/linux/blkdev.h | 4 +- 7 files changed, 194 insertions(+), 38 deletions(-) create mode 100644 Documentation/block/biovecs.txt (limited to 'include/linux') diff --git a/Documentation/block/biovecs.txt b/Documentation/block/biovecs.txt new file mode 100644 index 000000000000..74a32ad52f53 --- /dev/null +++ b/Documentation/block/biovecs.txt @@ -0,0 +1,111 @@ + +Immutable biovecs and biovec iterators: +======================================= + +Kent Overstreet + +As of 3.13, biovecs should never be modified after a bio has been submitted. +Instead, we have a new struct bvec_iter which represents a range of a biovec - +the iterator will be modified as the bio is completed, not the biovec. + +More specifically, old code that needed to partially complete a bio would +update bi_sector and bi_size, and advance bi_idx to the next biovec. If it +ended up partway through a biovec, it would increment bv_offset and decrement +bv_len by the number of bytes completed in that biovec. + +In the new scheme of things, everything that must be mutated in order to +partially complete a bio is segregated into struct bvec_iter: bi_sector, +bi_size and bi_idx have been moved there; and instead of modifying bv_offset +and bv_len, struct bvec_iter has bi_bvec_done, which represents the number of +bytes completed in the current bvec. + +There are a bunch of new helper macros for hiding the gory details - in +particular, presenting the illusion of partially completed biovecs so that +normal code doesn't have to deal with bi_bvec_done. + + * Driver code should no longer refer to biovecs directly; we now have + bio_iovec() and bio_iovec_iter() macros that return literal struct biovecs, + constructed from the raw biovecs but taking into account bi_bvec_done and + bi_size. + + bio_for_each_segment() has been updated to take a bvec_iter argument + instead of an integer (that corresponded to bi_idx); for a lot of code the + conversion just required changing the types of the arguments to + bio_for_each_segment(). + + * Advancing a bvec_iter is done with bio_advance_iter(); bio_advance() is a + wrapper around bio_advance_iter() that operates on bio->bi_iter, and also + advances the bio integrity's iter if present. + + There is a lower level advance function - bvec_iter_advance() - which takes + a pointer to a biovec, not a bio; this is used by the bio integrity code. + +What's all this get us? +======================= + +Having a real iterator, and making biovecs immutable, has a number of +advantages: + + * Before, iterating over bios was very awkward when you weren't processing + exactly one bvec at a time - for example, bio_copy_data() in fs/bio.c, + which copies the contents of one bio into another. Because the biovecs + wouldn't necessarily be the same size, the old code was tricky convoluted - + it had to walk two different bios at the same time, keeping both bi_idx and + and offset into the current biovec for each. + + The new code is much more straightforward - have a look. This sort of + pattern comes up in a lot of places; a lot of drivers were essentially open + coding bvec iterators before, and having common implementation considerably + simplifies a lot of code. + + * Before, any code that might need to use the biovec after the bio had been + completed (perhaps to copy the data somewhere else, or perhaps to resubmit + it somewhere else if there was an error) had to save the entire bvec array + - again, this was being done in a fair number of places. + + * Biovecs can be shared between multiple bios - a bvec iter can represent an + arbitrary range of an existing biovec, both starting and ending midway + through biovecs. This is what enables efficient splitting of arbitrary + bios. Note that this means we _only_ use bi_size to determine when we've + reached the end of a bio, not bi_vcnt - and the bio_iovec() macro takes + bi_size into account when constructing biovecs. + + * Splitting bios is now much simpler. The old bio_split() didn't even work on + bios with more than a single bvec! Now, we can efficiently split arbitrary + size bios - because the new bio can share the old bio's biovec. + + Care must be taken to ensure the biovec isn't freed while the split bio is + still using it, in case the original bio completes first, though. Using + bio_chain() when splitting bios helps with this. + + * Submitting partially completed bios is now perfectly fine - this comes up + occasionally in stacking block drivers and various code (e.g. md and + bcache) had some ugly workarounds for this. + + It used to be the case that submitting a partially completed bio would work + fine to _most_ devices, but since accessing the raw bvec array was the + norm, not all drivers would respect bi_idx and those would break. Now, + since all drivers _must_ go through the bvec iterator - and have been + audited to make sure they are - submitting partially completed bios is + perfectly fine. + +Other implications: +=================== + + * Almost all usage of bi_idx is now incorrect and has been removed; instead, + where previously you would have used bi_idx you'd now use a bvec_iter, + probably passing it to one of the helper macros. + + I.e. instead of using bio_iovec_idx() (or bio->bi_iovec[bio->bi_idx]), you + now use bio_iter_iovec(), which takes a bvec_iter and returns a + literal struct bio_vec - constructed on the fly from the raw biovec but + taking into account bi_bvec_done (and bi_size). + + * bi_vcnt can't be trusted or relied upon by driver code - i.e. anything that + doesn't actually own the bio. The reason is twofold: firstly, it's not + actually needed for iterating over the bio anymore - we only use bi_size. + Secondly, when cloning a bio and reusing (a portion of) the original bio's + biovec, in order to calculate bi_vcnt for the new bio we'd have to iterate + over all the biovecs in the new bio - which is silly as it's not needed. + + So, don't use bi_vcnt anymore. diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index f4e5440aba05..929468e1512a 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -1546,7 +1546,7 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio) err = _drbd_no_send_page(mdev, bvec.bv_page, bvec.bv_offset, bvec.bv_len, - bio_iter_last(bio, iter) + bio_iter_last(bvec, iter) ? 0 : MSG_MORE); if (err) return err; @@ -1565,7 +1565,7 @@ static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio) err = _drbd_send_page(mdev, bvec.bv_page, bvec.bv_offset, bvec.bv_len, - bio_iter_last(bio, iter) ? 0 : MSG_MORE); + bio_iter_last(bvec, iter) ? 0 : MSG_MORE); if (err) return err; } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index aa362f493216..55298db36b2d 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -278,7 +278,7 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req) */ rq_for_each_segment(bvec, req, iter) { flags = 0; - if (!rq_iter_last(req, iter)) + if (!rq_iter_last(bvec, iter)) flags = MSG_MORE; dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n", nbd->disk->disk_name, req, bvec.bv_len); diff --git a/fs/bio.c b/fs/bio.c index 8b7f14a95503..07b4b7afa695 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -532,13 +532,11 @@ void __bio_clone(struct bio *bio, struct bio *bio_src) * most users will be overriding ->bi_bdev with a new target, * so we don't set nor calculate new physical/hw segment counts here */ - bio->bi_iter.bi_sector = bio_src->bi_iter.bi_sector; bio->bi_bdev = bio_src->bi_bdev; bio->bi_flags |= 1 << BIO_CLONED; bio->bi_rw = bio_src->bi_rw; bio->bi_vcnt = bio_src->bi_vcnt; - bio->bi_iter.bi_size = bio_src->bi_iter.bi_size; - bio->bi_iter.bi_idx = bio_src->bi_iter.bi_idx; + bio->bi_iter = bio_src->bi_iter; } EXPORT_SYMBOL(__bio_clone); @@ -808,28 +806,7 @@ void bio_advance(struct bio *bio, unsigned bytes) if (bio_integrity(bio)) bio_integrity_advance(bio, bytes); - bio->bi_iter.bi_sector += bytes >> 9; - bio->bi_iter.bi_size -= bytes; - - if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK) - return; - - while (bytes) { - if (unlikely(bio->bi_iter.bi_idx >= bio->bi_vcnt)) { - WARN_ONCE(1, "bio idx %d >= vcnt %d\n", - bio->bi_iter.bi_idx, bio->bi_vcnt); - break; - } - - if (bytes >= bio_iovec(bio).bv_len) { - bytes -= bio_iovec(bio).bv_len; - bio->bi_iter.bi_idx++; - } else { - bio_iovec(bio).bv_len -= bytes; - bio_iovec(bio).bv_offset += bytes; - bytes = 0; - } - } + bio_advance_iter(bio, &bio->bi_iter, bytes); } EXPORT_SYMBOL(bio_advance); diff --git a/include/linux/bio.h b/include/linux/bio.h index c16adb5f69f8..04e592e74c92 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -64,11 +64,38 @@ #define bio_iovec_idx(bio, idx) (&((bio)->bi_io_vec[(idx)])) #define __bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) -#define bio_iter_iovec(bio, iter) ((bio)->bi_io_vec[(iter).bi_idx]) +#define __bvec_iter_bvec(bvec, iter) (&(bvec)[(iter).bi_idx]) -#define bio_page(bio) (bio_iovec((bio)).bv_page) -#define bio_offset(bio) (bio_iovec((bio)).bv_offset) -#define bio_iovec(bio) (*__bio_iovec(bio)) +#define bvec_iter_page(bvec, iter) \ + (__bvec_iter_bvec((bvec), (iter))->bv_page) + +#define bvec_iter_len(bvec, iter) \ + min((iter).bi_size, \ + __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done) + +#define bvec_iter_offset(bvec, iter) \ + (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done) + +#define bvec_iter_bvec(bvec, iter) \ +((struct bio_vec) { \ + .bv_page = bvec_iter_page((bvec), (iter)), \ + .bv_len = bvec_iter_len((bvec), (iter)), \ + .bv_offset = bvec_iter_offset((bvec), (iter)), \ +}) + +#define bio_iter_iovec(bio, iter) \ + bvec_iter_bvec((bio)->bi_io_vec, (iter)) + +#define bio_iter_page(bio, iter) \ + bvec_iter_page((bio)->bi_io_vec, (iter)) +#define bio_iter_len(bio, iter) \ + bvec_iter_len((bio)->bi_io_vec, (iter)) +#define bio_iter_offset(bio, iter) \ + bvec_iter_offset((bio)->bi_io_vec, (iter)) + +#define bio_page(bio) bio_iter_page((bio), (bio)->bi_iter) +#define bio_offset(bio) bio_iter_offset((bio), (bio)->bi_iter) +#define bio_iovec(bio) bio_iter_iovec((bio), (bio)->bi_iter) #define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_iter.bi_idx) #define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) @@ -145,16 +172,54 @@ static inline void *bio_data(struct bio *bio) bvl = bio_iovec_idx((bio), (i)), i < (bio)->bi_vcnt; \ i++) +static inline void bvec_iter_advance(struct bio_vec *bv, struct bvec_iter *iter, + unsigned bytes) +{ + WARN_ONCE(bytes > iter->bi_size, + "Attempted to advance past end of bvec iter\n"); + + while (bytes) { + unsigned len = min(bytes, bvec_iter_len(bv, *iter)); + + bytes -= len; + iter->bi_size -= len; + iter->bi_bvec_done += len; + + if (iter->bi_bvec_done == __bvec_iter_bvec(bv, *iter)->bv_len) { + iter->bi_bvec_done = 0; + iter->bi_idx++; + } + } +} + +#define for_each_bvec(bvl, bio_vec, iter, start) \ + for ((iter) = start; \ + (bvl) = bvec_iter_bvec((bio_vec), (iter)), \ + (iter).bi_size; \ + bvec_iter_advance((bio_vec), &(iter), (bvl).bv_len)) + + +static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, + unsigned bytes) +{ + iter->bi_sector += bytes >> 9; + + if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK) + iter->bi_size -= bytes; + else + bvec_iter_advance(bio->bi_io_vec, iter, bytes); +} + #define __bio_for_each_segment(bvl, bio, iter, start) \ for (iter = (start); \ - bvl = bio_iter_iovec((bio), (iter)), \ - (iter).bi_idx < (bio)->bi_vcnt; \ - (iter).bi_idx++) + (iter).bi_size && \ + ((bvl = bio_iter_iovec((bio), (iter))), 1); \ + bio_advance_iter((bio), &(iter), (bvl).bv_len)) #define bio_for_each_segment(bvl, bio, iter) \ __bio_for_each_segment(bvl, bio, iter, (bio)->bi_iter) -#define bio_iter_last(bio, iter) ((iter).bi_idx == (bio)->bi_vcnt - 1) +#define bio_iter_last(bvec, iter) ((iter).bi_size == (bvec).bv_len) /* * get a reference to a bio, so it won't disappear. the intended use is diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 29b5b84d8a29..d369f8f6af79 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -34,6 +34,9 @@ struct bvec_iter { unsigned int bi_size; /* residual I/O count */ unsigned int bi_idx; /* current index into bvl_vec */ + + unsigned int bi_bvec_done; /* number of bytes completed in + current bvec */ }; /* diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 337b92a54658..02cb6f0ea71d 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -750,9 +750,9 @@ struct req_iterator { __rq_for_each_bio(_iter.bio, _rq) \ bio_for_each_segment(bvl, _iter.bio, _iter.iter) -#define rq_iter_last(rq, _iter) \ +#define rq_iter_last(bvec, _iter) \ (_iter.bio->bi_next == NULL && \ - bio_iter_last(_iter.bio, _iter.iter)) + bio_iter_last(bvec, _iter.iter)) #ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE # error "You should define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform" -- cgit v1.2.3-59-g8ed1b From d57a5f7c6605f15f3b5134837e68b448a7cea88e Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sat, 23 Nov 2013 17:20:16 -0800 Subject: bio-integrity: Convert to bvec_iter The bio integrity is also stored in a bvec array, so if we use the bvec iter code we just added, the integrity code won't need to implement its own iteration stuff (bio_integrity_mark_head(), bio_integrity_mark_tail()) Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: "Martin K. Petersen" Cc: "James E.J. Bottomley" --- block/blk-integrity.c | 40 ++++++++++--------- drivers/scsi/sd_dif.c | 30 +++++++------- fs/bio-integrity.c | 108 ++++++++++++-------------------------------------- include/linux/bio.h | 19 ++++----- 4 files changed, 71 insertions(+), 126 deletions(-) (limited to 'include/linux') diff --git a/block/blk-integrity.c b/block/blk-integrity.c index 03cf7179e8ef..7fbab84399e6 100644 --- a/block/blk-integrity.c +++ b/block/blk-integrity.c @@ -43,30 +43,32 @@ static const char *bi_unsupported_name = "unsupported"; */ int blk_rq_count_integrity_sg(struct request_queue *q, struct bio *bio) { - struct bio_vec *iv, *ivprv = NULL; + struct bio_vec iv, ivprv = { NULL }; unsigned int segments = 0; unsigned int seg_size = 0; - unsigned int i = 0; + struct bvec_iter iter; + int prev = 0; - bio_for_each_integrity_vec(iv, bio, i) { + bio_for_each_integrity_vec(iv, bio, iter) { - if (ivprv) { - if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv)) + if (prev) { + if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv)) goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv)) + if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv)) goto new_segment; - if (seg_size + iv->bv_len > queue_max_segment_size(q)) + if (seg_size + iv.bv_len > queue_max_segment_size(q)) goto new_segment; - seg_size += iv->bv_len; + seg_size += iv.bv_len; } else { new_segment: segments++; - seg_size = iv->bv_len; + seg_size = iv.bv_len; } + prev = 1; ivprv = iv; } @@ -87,24 +89,25 @@ EXPORT_SYMBOL(blk_rq_count_integrity_sg); int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio, struct scatterlist *sglist) { - struct bio_vec *iv, *ivprv = NULL; + struct bio_vec iv, ivprv = { NULL }; struct scatterlist *sg = NULL; unsigned int segments = 0; - unsigned int i = 0; + struct bvec_iter iter; + int prev = 0; - bio_for_each_integrity_vec(iv, bio, i) { + bio_for_each_integrity_vec(iv, bio, iter) { - if (ivprv) { - if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv)) + if (prev) { + if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv)) goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv)) + if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv)) goto new_segment; - if (sg->length + iv->bv_len > queue_max_segment_size(q)) + if (sg->length + iv.bv_len > queue_max_segment_size(q)) goto new_segment; - sg->length += iv->bv_len; + sg->length += iv.bv_len; } else { new_segment: if (!sg) @@ -114,10 +117,11 @@ new_segment: sg = sg_next(sg); } - sg_set_page(sg, iv->bv_page, iv->bv_len, iv->bv_offset); + sg_set_page(sg, iv.bv_page, iv.bv_len, iv.bv_offset); segments++; } + prev = 1; ivprv = iv; } diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c index 6174ca4ea275..a7a691d0af7d 100644 --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c @@ -365,7 +365,6 @@ void sd_dif_prepare(struct request *rq, sector_t hw_sector, struct bio *bio; struct scsi_disk *sdkp; struct sd_dif_tuple *sdt; - unsigned int i, j; u32 phys, virt; sdkp = rq->bio->bi_bdev->bd_disk->private_data; @@ -376,19 +375,21 @@ void sd_dif_prepare(struct request *rq, sector_t hw_sector, phys = hw_sector & 0xffffffff; __rq_for_each_bio(bio, rq) { - struct bio_vec *iv; + struct bio_vec iv; + struct bvec_iter iter; + unsigned int j; /* Already remapped? */ if (bio_flagged(bio, BIO_MAPPED_INTEGRITY)) break; - virt = bio->bi_integrity->bip_sector & 0xffffffff; + virt = bio->bi_integrity->bip_iter.bi_sector & 0xffffffff; - bip_for_each_vec(iv, bio->bi_integrity, i) { - sdt = kmap_atomic(iv->bv_page) - + iv->bv_offset; + bip_for_each_vec(iv, bio->bi_integrity, iter) { + sdt = kmap_atomic(iv.bv_page) + + iv.bv_offset; - for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) { + for (j = 0; j < iv.bv_len; j += tuple_sz, sdt++) { if (be32_to_cpu(sdt->ref_tag) == virt) sdt->ref_tag = cpu_to_be32(phys); @@ -414,7 +415,7 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) struct scsi_disk *sdkp; struct bio *bio; struct sd_dif_tuple *sdt; - unsigned int i, j, sectors, sector_sz; + unsigned int j, sectors, sector_sz; u32 phys, virt; sdkp = scsi_disk(scmd->request->rq_disk); @@ -430,15 +431,16 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) phys >>= 3; __rq_for_each_bio(bio, scmd->request) { - struct bio_vec *iv; + struct bio_vec iv; + struct bvec_iter iter; - virt = bio->bi_integrity->bip_sector & 0xffffffff; + virt = bio->bi_integrity->bip_iter.bi_sector & 0xffffffff; - bip_for_each_vec(iv, bio->bi_integrity, i) { - sdt = kmap_atomic(iv->bv_page) - + iv->bv_offset; + bip_for_each_vec(iv, bio->bi_integrity, iter) { + sdt = kmap_atomic(iv.bv_page) + + iv.bv_offset; - for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) { + for (j = 0; j < iv.bv_len; j += tuple_sz, sdt++) { if (sectors == 0) { kunmap_atomic(sdt); diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index 9127db86f315..fed744b8c9e5 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c @@ -134,8 +134,7 @@ int bio_integrity_add_page(struct bio *bio, struct page *page, return 0; } - iv = bip_vec_idx(bip, bip->bip_vcnt); - BUG_ON(iv == NULL); + iv = bip->bip_vec + bip->bip_vcnt; iv->bv_page = page; iv->bv_len = len; @@ -203,6 +202,12 @@ static inline unsigned int bio_integrity_hw_sectors(struct blk_integrity *bi, return sectors; } +static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi, + unsigned int sectors) +{ + return bio_integrity_hw_sectors(bi, sectors) * bi->tuple_size; +} + /** * bio_integrity_tag_size - Retrieve integrity tag space * @bio: bio to inspect @@ -235,9 +240,9 @@ int bio_integrity_tag(struct bio *bio, void *tag_buf, unsigned int len, int set) nr_sectors = bio_integrity_hw_sectors(bi, DIV_ROUND_UP(len, bi->tag_size)); - if (nr_sectors * bi->tuple_size > bip->bip_size) { - printk(KERN_ERR "%s: tag too big for bio: %u > %u\n", - __func__, nr_sectors * bi->tuple_size, bip->bip_size); + if (nr_sectors * bi->tuple_size > bip->bip_iter.bi_size) { + printk(KERN_ERR "%s: tag too big for bio: %u > %u\n", __func__, + nr_sectors * bi->tuple_size, bip->bip_iter.bi_size); return -1; } @@ -322,7 +327,7 @@ static void bio_integrity_generate(struct bio *bio) sector += sectors; prot_buf += sectors * bi->tuple_size; total += sectors * bi->tuple_size; - BUG_ON(total > bio->bi_integrity->bip_size); + BUG_ON(total > bio->bi_integrity->bip_iter.bi_size); kunmap_atomic(kaddr); } @@ -387,8 +392,8 @@ int bio_integrity_prep(struct bio *bio) bip->bip_owns_buf = 1; bip->bip_buf = buf; - bip->bip_size = len; - bip->bip_sector = bio->bi_iter.bi_sector; + bip->bip_iter.bi_size = len; + bip->bip_iter.bi_sector = bio->bi_iter.bi_sector; /* Map it */ offset = offset_in_page(buf); @@ -444,7 +449,7 @@ static int bio_integrity_verify(struct bio *bio) struct blk_integrity_exchg bix; struct bio_vec bv; struct bvec_iter iter; - sector_t sector = bio->bi_integrity->bip_sector; + sector_t sector = bio->bi_integrity->bip_iter.bi_sector; unsigned int sectors, total, ret; void *prot_buf = bio->bi_integrity->bip_buf; @@ -470,7 +475,7 @@ static int bio_integrity_verify(struct bio *bio) sector += sectors; prot_buf += sectors * bi->tuple_size; total += sectors * bi->tuple_size; - BUG_ON(total > bio->bi_integrity->bip_size); + BUG_ON(total > bio->bi_integrity->bip_iter.bi_size); kunmap_atomic(kaddr); } @@ -534,56 +539,6 @@ void bio_integrity_endio(struct bio *bio, int error) } EXPORT_SYMBOL(bio_integrity_endio); -/** - * bio_integrity_mark_head - Advance bip_vec skip bytes - * @bip: Integrity vector to advance - * @skip: Number of bytes to advance it - */ -void bio_integrity_mark_head(struct bio_integrity_payload *bip, - unsigned int skip) -{ - struct bio_vec *iv; - unsigned int i; - - bip_for_each_vec(iv, bip, i) { - if (skip == 0) { - bip->bip_idx = i; - return; - } else if (skip >= iv->bv_len) { - skip -= iv->bv_len; - } else { /* skip < iv->bv_len) */ - iv->bv_offset += skip; - iv->bv_len -= skip; - bip->bip_idx = i; - return; - } - } -} - -/** - * bio_integrity_mark_tail - Truncate bip_vec to be len bytes long - * @bip: Integrity vector to truncate - * @len: New length of integrity vector - */ -void bio_integrity_mark_tail(struct bio_integrity_payload *bip, - unsigned int len) -{ - struct bio_vec *iv; - unsigned int i; - - bip_for_each_vec(iv, bip, i) { - if (len == 0) { - bip->bip_vcnt = i; - return; - } else if (len >= iv->bv_len) { - len -= iv->bv_len; - } else { /* len < iv->bv_len) */ - iv->bv_len = len; - len = 0; - } - } -} - /** * bio_integrity_advance - Advance integrity vector * @bio: bio whose integrity vector to update @@ -597,13 +552,9 @@ void bio_integrity_advance(struct bio *bio, unsigned int bytes_done) { struct bio_integrity_payload *bip = bio->bi_integrity; struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - unsigned int nr_sectors; + unsigned bytes = bio_integrity_bytes(bi, bytes_done >> 9); - BUG_ON(bip == NULL); - BUG_ON(bi == NULL); - - nr_sectors = bio_integrity_hw_sectors(bi, bytes_done >> 9); - bio_integrity_mark_head(bip, nr_sectors * bi->tuple_size); + bvec_iter_advance(bip->bip_vec, &bip->bip_iter, bytes); } EXPORT_SYMBOL(bio_integrity_advance); @@ -623,16 +574,9 @@ void bio_integrity_trim(struct bio *bio, unsigned int offset, { struct bio_integrity_payload *bip = bio->bi_integrity; struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - unsigned int nr_sectors; - BUG_ON(bip == NULL); - BUG_ON(bi == NULL); - BUG_ON(!bio_flagged(bio, BIO_CLONED)); - - nr_sectors = bio_integrity_hw_sectors(bi, sectors); - bip->bip_sector = bip->bip_sector + offset; - bio_integrity_mark_head(bip, offset * bi->tuple_size); - bio_integrity_mark_tail(bip, sectors * bi->tuple_size); + bio_integrity_advance(bio, offset << 9); + bip->bip_iter.bi_size = bio_integrity_bytes(bi, sectors); } EXPORT_SYMBOL(bio_integrity_trim); @@ -662,8 +606,8 @@ void bio_integrity_split(struct bio *bio, struct bio_pair *bp, int sectors) bp->bio1.bi_integrity = &bp->bip1; bp->bio2.bi_integrity = &bp->bip2; - bp->iv1 = bip->bip_vec[bip->bip_idx]; - bp->iv2 = bip->bip_vec[bip->bip_idx]; + bp->iv1 = bip->bip_vec[bip->bip_iter.bi_idx]; + bp->iv2 = bip->bip_vec[bip->bip_iter.bi_idx]; bp->bip1.bip_vec = &bp->iv1; bp->bip2.bip_vec = &bp->iv2; @@ -672,11 +616,12 @@ void bio_integrity_split(struct bio *bio, struct bio_pair *bp, int sectors) bp->iv2.bv_offset += sectors * bi->tuple_size; bp->iv2.bv_len -= sectors * bi->tuple_size; - bp->bip1.bip_sector = bio->bi_integrity->bip_sector; - bp->bip2.bip_sector = bio->bi_integrity->bip_sector + nr_sectors; + bp->bip1.bip_iter.bi_sector = bio->bi_integrity->bip_iter.bi_sector; + bp->bip2.bip_iter.bi_sector = + bio->bi_integrity->bip_iter.bi_sector + nr_sectors; bp->bip1.bip_vcnt = bp->bip2.bip_vcnt = 1; - bp->bip1.bip_idx = bp->bip2.bip_idx = 0; + bp->bip1.bip_iter.bi_idx = bp->bip2.bip_iter.bi_idx = 0; } EXPORT_SYMBOL(bio_integrity_split); @@ -704,9 +649,8 @@ int bio_integrity_clone(struct bio *bio, struct bio *bio_src, memcpy(bip->bip_vec, bip_src->bip_vec, bip_src->bip_vcnt * sizeof(struct bio_vec)); - bip->bip_sector = bip_src->bip_sector; bip->bip_vcnt = bip_src->bip_vcnt; - bip->bip_idx = bip_src->bip_idx; + bip->bip_iter = bip_src->bip_iter; return 0; } diff --git a/include/linux/bio.h b/include/linux/bio.h index 04e592e74c92..930cb73c894b 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -244,16 +244,15 @@ static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, struct bio_integrity_payload { struct bio *bip_bio; /* parent bio */ - sector_t bip_sector; /* virtual start sector */ + struct bvec_iter bip_iter; + /* kill - should just use bip_vec */ void *bip_buf; /* generated integrity data */ - bio_end_io_t *bip_end_io; /* saved I/O completion fn */ - unsigned int bip_size; + bio_end_io_t *bip_end_io; /* saved I/O completion fn */ unsigned short bip_slab; /* slab the bip came from */ unsigned short bip_vcnt; /* # of integrity bio_vecs */ - unsigned short bip_idx; /* current bip_vec index */ unsigned bip_owns_buf:1; /* should free bip_buf */ struct work_struct bip_work; /* I/O completion */ @@ -626,16 +625,12 @@ struct biovec_slab { #if defined(CONFIG_BLK_DEV_INTEGRITY) -#define bip_vec_idx(bip, idx) (&(bip->bip_vec[(idx)])) -#define bip_vec(bip) bip_vec_idx(bip, 0) -#define __bip_for_each_vec(bvl, bip, i, start_idx) \ - for (bvl = bip_vec_idx((bip), (start_idx)), i = (start_idx); \ - i < (bip)->bip_vcnt; \ - bvl++, i++) -#define bip_for_each_vec(bvl, bip, i) \ - __bip_for_each_vec(bvl, bip, i, (bip)->bip_idx) +#define bip_vec_idx(bip, idx) (&(bip->bip_vec[(idx)])) + +#define bip_for_each_vec(bvl, bip, iter) \ + for_each_bvec(bvl, (bip)->bip_vec, iter, (bip)->bip_iter) #define bio_for_each_integrity_vec(_bvl, _bio, _iter) \ for_each_bio(_bio) \ -- cgit v1.2.3-59-g8ed1b From 458b76ed2f9517becb74dcc8eedd70d3068ea6e4 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Tue, 24 Sep 2013 16:26:05 -0700 Subject: block: Kill bio_segments()/bi_vcnt usage When we start sharing biovecs, keeping bi_vcnt accurate for splits is going to be error prone - and unnecessary, if we refactor some code. So bio_segments() has to go - but most of the existing users just needed to know if the bio had multiple segments, which is easier - add a bio_multiple_segments() for them. (Two of the current uses of bio_segments() are going to go away in a couple patches, but the current implementation of bio_segments() is unsafe as soon as we start doing driver conversions for immutable biovecs - so implement a dumb version for bisectability, it'll go away in a couple patches) Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: Neil Brown Cc: Nagalakshmi Nandigama Cc: Sreekanth Reddy Cc: "James E.J. Bottomley" --- drivers/block/ps3disk.c | 7 ++- drivers/md/bcache/io.c | 53 +++++++++------------ drivers/md/raid0.c | 2 +- drivers/md/raid10.c | 2 +- drivers/message/fusion/mptsas.c | 8 ++-- drivers/scsi/libsas/sas_expander.c | 8 ++-- drivers/scsi/mpt2sas/mpt2sas_transport.c | 10 ++-- drivers/scsi/mpt3sas/mpt3sas_transport.c | 8 ++-- fs/bio.c | 2 +- include/linux/bio.h | 81 +++++++++++++++++++------------- 10 files changed, 94 insertions(+), 87 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index 1c6edb9a9960..c120d70d3fb3 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c @@ -101,10 +101,9 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, rq_for_each_segment(bvec, req, iter) { unsigned long flags; - dev_dbg(&dev->sbd.core, - "%s:%u: bio %u: %u segs %u sectors from %lu\n", - __func__, __LINE__, i, bio_segments(iter.bio), - bio_sectors(iter.bio), iter.bio->bi_iter.bi_sector); + dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u sectors from %lu\n", + __func__, __LINE__, i, bio_sectors(iter.bio), + iter.bio->bi_iter.bi_sector); size = bvec.bv_len; buf = bvec_kmap_irq(&bvec, &flags); diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index 9b5b6a41a9b6..6e04f3bb0286 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -24,7 +24,8 @@ static void bch_generic_make_request_hack(struct bio *bio) if (bio->bi_iter.bi_idx) { struct bio_vec bv; struct bvec_iter iter; - struct bio *clone = bio_alloc(GFP_NOIO, bio_segments(bio)); + unsigned segs = bio_segments(bio); + struct bio *clone = bio_alloc(GFP_NOIO, segs); bio_for_each_segment(bv, bio, iter) clone->bi_io_vec[clone->bi_vcnt++] = bv; @@ -32,7 +33,7 @@ static void bch_generic_make_request_hack(struct bio *bio) clone->bi_iter.bi_sector = bio->bi_iter.bi_sector; clone->bi_bdev = bio->bi_bdev; clone->bi_rw = bio->bi_rw; - clone->bi_vcnt = bio_segments(bio); + clone->bi_vcnt = segs; clone->bi_iter.bi_size = bio->bi_iter.bi_size; clone->bi_private = bio; @@ -133,40 +134,32 @@ out: static unsigned bch_bio_max_sectors(struct bio *bio) { - unsigned ret = bio_sectors(bio); struct request_queue *q = bdev_get_queue(bio->bi_bdev); - unsigned max_segments = min_t(unsigned, BIO_MAX_PAGES, - queue_max_segments(q)); + struct bio_vec bv; + struct bvec_iter iter; + unsigned ret = 0, seg = 0; if (bio->bi_rw & REQ_DISCARD) - return min(ret, q->limits.max_discard_sectors); - - if (bio_segments(bio) > max_segments || - q->merge_bvec_fn) { - struct bio_vec bv; - struct bvec_iter iter; - unsigned seg = 0; - - ret = 0; + return min(bio_sectors(bio), q->limits.max_discard_sectors); - bio_for_each_segment(bv, bio, iter) { - struct bvec_merge_data bvm = { - .bi_bdev = bio->bi_bdev, - .bi_sector = bio->bi_iter.bi_sector, - .bi_size = ret << 9, - .bi_rw = bio->bi_rw, - }; - - if (seg == max_segments) - break; + bio_for_each_segment(bv, bio, iter) { + struct bvec_merge_data bvm = { + .bi_bdev = bio->bi_bdev, + .bi_sector = bio->bi_iter.bi_sector, + .bi_size = ret << 9, + .bi_rw = bio->bi_rw, + }; + + if (seg == min_t(unsigned, BIO_MAX_PAGES, + queue_max_segments(q))) + break; - if (q->merge_bvec_fn && - q->merge_bvec_fn(q, &bvm, &bv) < (int) bv.bv_len) - break; + if (q->merge_bvec_fn && + q->merge_bvec_fn(q, &bvm, &bv) < (int) bv.bv_len) + break; - seg++; - ret += bv.bv_len >> 9; - } + seg++; + ret += bv.bv_len >> 9; } ret = min(ret, queue_max_sectors(q)); diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index e38d1d3226f3..8ee1a6c658b4 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -528,7 +528,7 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio) sector_t sector = bio->bi_iter.bi_sector; struct bio_pair *bp; /* Sanity check -- queue functions should prevent this happening */ - if (bio_segments(bio) > 1) + if (bio_multiple_segments(bio)) goto bad_map; /* This is a one page bio that upper layers * refuse to split for us, so we need to split it. diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index dbf3b63c2754..ac4bfa438c57 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1188,7 +1188,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) || conf->prev.near_copies < conf->prev.raid_disks))) { struct bio_pair *bp; /* Sanity check -- queue functions should prevent this happening */ - if (bio_segments(bio) > 1) + if (bio_multiple_segments(bio)) goto bad_map; /* This is a one page bio that upper layers * refuse to split for us, so we need to split it. diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index dd239bdbfcb4..00d339c361fc 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c @@ -2235,10 +2235,10 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, } /* do we need to support multiple segments? */ - if (bio_segments(req->bio) > 1 || bio_segments(rsp->bio) > 1) { - printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n", - ioc->name, __func__, bio_segments(req->bio), blk_rq_bytes(req), - bio_segments(rsp->bio), blk_rq_bytes(rsp)); + if (bio_multiple_segments(req->bio) || + bio_multiple_segments(rsp->bio)) { + printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u, rsp %u\n", + ioc->name, __func__, blk_rq_bytes(req), blk_rq_bytes(rsp)); return -EINVAL; } diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c index 446b85110a1f..0cac7d8fd0f7 100644 --- a/drivers/scsi/libsas/sas_expander.c +++ b/drivers/scsi/libsas/sas_expander.c @@ -2163,10 +2163,10 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, } /* do we need to support multiple segments? */ - if (bio_segments(req->bio) > 1 || bio_segments(rsp->bio) > 1) { - printk("%s: multiple segments req %u %u, rsp %u %u\n", - __func__, bio_segments(req->bio), blk_rq_bytes(req), - bio_segments(rsp->bio), blk_rq_bytes(rsp)); + if (bio_multiple_segments(req->bio) || + bio_multiple_segments(rsp->bio)) { + printk("%s: multiple segments req %u, rsp %u\n", + __func__, blk_rq_bytes(req), blk_rq_bytes(rsp)); return -EINVAL; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index 7143e86af326..410f4a3e8888 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -1943,7 +1943,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, ioc->transport_cmds.status = MPT2_CMD_PENDING; /* Check if the request is split across multiple segments */ - if (bio_segments(req->bio) > 1) { + if (bio_multiple_segments(req->bio)) { u32 offset = 0; /* Allocate memory and copy the request */ @@ -1975,7 +1975,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, /* Check if the response needs to be populated across * multiple segments */ - if (bio_segments(rsp->bio) > 1) { + if (bio_multiple_segments(rsp->bio)) { pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp), &pci_dma_in); if (!pci_addr_in) { @@ -2042,7 +2042,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - if (bio_segments(req->bio) > 1) { + if (bio_multiple_segments(req->bio)) { ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4), pci_dma_out); } else { @@ -2058,7 +2058,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST); sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - if (bio_segments(rsp->bio) > 1) { + if (bio_multiple_segments(rsp->bio)) { ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4), pci_dma_in); } else { @@ -2103,7 +2103,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, le16_to_cpu(mpi_reply->ResponseDataLength); /* check if the resp needs to be copied from the allocated * pci mem */ - if (bio_segments(rsp->bio) > 1) { + if (bio_multiple_segments(rsp->bio)) { u32 offset = 0; u32 bytes_to_copy = le16_to_cpu(mpi_reply->ResponseDataLength); diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 196a67f2e95f..65170cb1a00f 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -1926,7 +1926,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, ioc->transport_cmds.status = MPT3_CMD_PENDING; /* Check if the request is split across multiple segments */ - if (req->bio->bi_vcnt > 1) { + if (bio_multiple_segments(req->bio)) { u32 offset = 0; /* Allocate memory and copy the request */ @@ -1958,7 +1958,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, /* Check if the response needs to be populated across * multiple segments */ - if (rsp->bio->bi_vcnt > 1) { + if (bio_multiple_segments(rsp->bio)) { pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp), &pci_dma_in); if (!pci_addr_in) { @@ -2019,7 +2019,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); psge = &mpi_request->SGL; - if (req->bio->bi_vcnt > 1) + if (bio_multiple_segments(req->bio)) ioc->build_sg(ioc, psge, pci_dma_out, (blk_rq_bytes(req) - 4), pci_dma_in, (blk_rq_bytes(rsp) + 4)); else @@ -2064,7 +2064,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, /* check if the resp needs to be copied from the allocated * pci mem */ - if (rsp->bio->bi_vcnt > 1) { + if (bio_multiple_segments(rsp->bio)) { u32 offset = 0; u32 bytes_to_copy = le16_to_cpu(mpi_reply->ResponseDataLength); diff --git a/fs/bio.c b/fs/bio.c index f61e59b38815..e32f2ffc3f33 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -1733,7 +1733,7 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors) trace_block_split(bdev_get_queue(bi->bi_bdev), bi, bi->bi_iter.bi_sector + first_sectors); - BUG_ON(bio_segments(bi) > 1); + BUG_ON(bio_multiple_segments(bi)); atomic_set(&bp->cnt, 3); bp->error = 0; bp->bio1 = *bi; diff --git a/include/linux/bio.h b/include/linux/bio.h index 930cb73c894b..aea9896a6289 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -97,13 +97,46 @@ #define bio_offset(bio) bio_iter_offset((bio), (bio)->bi_iter) #define bio_iovec(bio) bio_iter_iovec((bio), (bio)->bi_iter) -#define bio_segments(bio) ((bio)->bi_vcnt - (bio)->bi_iter.bi_idx) +#define bio_multiple_segments(bio) \ + ((bio)->bi_iter.bi_size != bio_iovec(bio).bv_len) #define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) #define bio_end_sector(bio) ((bio)->bi_iter.bi_sector + bio_sectors((bio))) +/* + * Check whether this bio carries any data or not. A NULL bio is allowed. + */ +static inline bool bio_has_data(struct bio *bio) +{ + if (bio && + bio->bi_iter.bi_size && + !(bio->bi_rw & REQ_DISCARD)) + return true; + + return false; +} + +static inline bool bio_is_rw(struct bio *bio) +{ + if (!bio_has_data(bio)) + return false; + + if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK) + return false; + + return true; +} + +static inline bool bio_mergeable(struct bio *bio) +{ + if (bio->bi_rw & REQ_NOMERGE_FLAGS) + return false; + + return true; +} + static inline unsigned int bio_cur_bytes(struct bio *bio) { - if (bio->bi_vcnt) + if (bio_has_data(bio)) return bio_iovec(bio).bv_len; else /* dataless requests such as discard */ return bio->bi_iter.bi_size; @@ -111,7 +144,7 @@ static inline unsigned int bio_cur_bytes(struct bio *bio) static inline void *bio_data(struct bio *bio) { - if (bio->bi_vcnt) + if (bio_has_data(bio)) return page_address(bio_page(bio)) + bio_offset(bio); return NULL; @@ -221,6 +254,18 @@ static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, #define bio_iter_last(bvec, iter) ((iter).bi_size == (bvec).bv_len) +static inline unsigned bio_segments(struct bio *bio) +{ + unsigned segs = 0; + struct bio_vec bv; + struct bvec_iter iter; + + bio_for_each_segment(bv, bio, iter) + segs++; + + return segs; +} + /* * get a reference to a bio, so it won't disappear. the intended use is * something like: @@ -434,36 +479,6 @@ static inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx, __bio_kmap_irq((bio), (bio)->bi_iter.bi_idx, (flags)) #define bio_kunmap_irq(buf,flags) __bio_kunmap_irq(buf, flags) -/* - * Check whether this bio carries any data or not. A NULL bio is allowed. - */ -static inline bool bio_has_data(struct bio *bio) -{ - if (bio && bio->bi_vcnt) - return true; - - return false; -} - -static inline bool bio_is_rw(struct bio *bio) -{ - if (!bio_has_data(bio)) - return false; - - if (bio->bi_rw & REQ_WRITE_SAME) - return false; - - return true; -} - -static inline bool bio_mergeable(struct bio *bio) -{ - if (bio->bi_rw & REQ_NOMERGE_FLAGS) - return false; - - return true; -} - /* * BIO list management for use by remapping drivers (e.g. DM or MD) and loop. * -- cgit v1.2.3-59-g8ed1b From 003b5c5719f159f4f4bf97511c4702a0638313dd Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Fri, 11 Oct 2013 15:45:43 -0700 Subject: block: Convert drivers to immutable biovecs Now that we've got a mechanism for immutable biovecs - bi_iter.bi_bvec_done - we need to convert drivers to use primitives that respect it instead of using the bvec array directly. Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: NeilBrown Cc: Alasdair Kergon Cc: dm-devel@redhat.com --- drivers/block/umem.c | 50 ++++++++++++++++++++++-------------------------- drivers/md/dm-crypt.c | 49 +++++++++++++++++------------------------------ drivers/md/dm-io.c | 31 ++++++++++++++++-------------- drivers/md/dm-raid1.c | 8 ++++---- drivers/md/dm-verity.c | 52 ++++++++++++++------------------------------------ fs/bio.c | 14 +++++++++++--- include/linux/dm-io.h | 4 ++-- 7 files changed, 89 insertions(+), 119 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/umem.c b/drivers/block/umem.c index dab4f1afeae9..4cf81b5bf0f7 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -108,8 +108,7 @@ struct cardinfo { * have been written */ struct bio *bio, *currentbio, **biotail; - int current_idx; - sector_t current_sector; + struct bvec_iter current_iter; struct request_queue *queue; @@ -118,7 +117,7 @@ struct cardinfo { struct mm_dma_desc *desc; int cnt, headcnt; struct bio *bio, **biotail; - int idx; + struct bvec_iter iter; } mm_pages[2]; #define DESC_PER_PAGE ((PAGE_SIZE*2)/sizeof(struct mm_dma_desc)) @@ -344,16 +343,13 @@ static int add_bio(struct cardinfo *card) dma_addr_t dma_handle; int offset; struct bio *bio; - struct bio_vec *vec; - int idx; + struct bio_vec vec; int rw; - int len; bio = card->currentbio; if (!bio && card->bio) { card->currentbio = card->bio; - card->current_idx = card->bio->bi_iter.bi_idx; - card->current_sector = card->bio->bi_iter.bi_sector; + card->current_iter = card->bio->bi_iter; card->bio = card->bio->bi_next; if (card->bio == NULL) card->biotail = &card->bio; @@ -362,18 +358,17 @@ static int add_bio(struct cardinfo *card) } if (!bio) return 0; - idx = card->current_idx; rw = bio_rw(bio); if (card->mm_pages[card->Ready].cnt >= DESC_PER_PAGE) return 0; - vec = bio_iovec_idx(bio, idx); - len = vec->bv_len; + vec = bio_iter_iovec(bio, card->current_iter); + dma_handle = pci_map_page(card->dev, - vec->bv_page, - vec->bv_offset, - len, + vec.bv_page, + vec.bv_offset, + vec.bv_len, (rw == READ) ? PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); @@ -381,7 +376,7 @@ static int add_bio(struct cardinfo *card) desc = &p->desc[p->cnt]; p->cnt++; if (p->bio == NULL) - p->idx = idx; + p->iter = card->current_iter; if ((p->biotail) != &bio->bi_next) { *(p->biotail) = bio; p->biotail = &(bio->bi_next); @@ -391,8 +386,8 @@ static int add_bio(struct cardinfo *card) desc->data_dma_handle = dma_handle; desc->pci_addr = cpu_to_le64((u64)desc->data_dma_handle); - desc->local_addr = cpu_to_le64(card->current_sector << 9); - desc->transfer_size = cpu_to_le32(len); + desc->local_addr = cpu_to_le64(card->current_iter.bi_sector << 9); + desc->transfer_size = cpu_to_le32(vec.bv_len); offset = (((char *)&desc->sem_control_bits) - ((char *)p->desc)); desc->sem_addr = cpu_to_le64((u64)(p->page_dma+offset)); desc->zero1 = desc->zero2 = 0; @@ -407,10 +402,9 @@ static int add_bio(struct cardinfo *card) desc->control_bits |= cpu_to_le32(DMASCR_TRANSFER_READ); desc->sem_control_bits = desc->control_bits; - card->current_sector += (len >> 9); - idx++; - card->current_idx = idx; - if (idx >= bio->bi_vcnt) + + bio_advance_iter(bio, &card->current_iter, vec.bv_len); + if (!card->current_iter.bi_size) card->currentbio = NULL; return 1; @@ -439,23 +433,25 @@ static void process_page(unsigned long data) struct mm_dma_desc *desc = &page->desc[page->headcnt]; int control = le32_to_cpu(desc->sem_control_bits); int last = 0; - int idx; + struct bio_vec vec; if (!(control & DMASCR_DMA_COMPLETE)) { control = dma_status; last = 1; } + page->headcnt++; - idx = page->idx; - page->idx++; - if (page->idx >= bio->bi_vcnt) { + vec = bio_iter_iovec(bio, page->iter); + bio_advance_iter(bio, &page->iter, vec.bv_len); + + if (!page->iter.bi_size) { page->bio = bio->bi_next; if (page->bio) - page->idx = page->bio->bi_iter.bi_idx; + page->iter = page->bio->bi_iter; } pci_unmap_page(card->dev, desc->data_dma_handle, - bio_iovec_idx(bio, idx)->bv_len, + vec.bv_len, (control & DMASCR_TRANSFER_READ) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); if (control & DMASCR_HARD_ERROR) { diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 1e2e5465d28e..784695d22fde 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -39,10 +39,8 @@ struct convert_context { struct completion restart; struct bio *bio_in; struct bio *bio_out; - unsigned int offset_in; - unsigned int offset_out; - unsigned int idx_in; - unsigned int idx_out; + struct bvec_iter iter_in; + struct bvec_iter iter_out; sector_t cc_sector; atomic_t cc_pending; }; @@ -826,10 +824,10 @@ static void crypt_convert_init(struct crypt_config *cc, { ctx->bio_in = bio_in; ctx->bio_out = bio_out; - ctx->offset_in = 0; - ctx->offset_out = 0; - ctx->idx_in = bio_in ? bio_in->bi_iter.bi_idx : 0; - ctx->idx_out = bio_out ? bio_out->bi_iter.bi_idx : 0; + if (bio_in) + ctx->iter_in = bio_in->bi_iter; + if (bio_out) + ctx->iter_out = bio_out->bi_iter; ctx->cc_sector = sector + cc->iv_offset; init_completion(&ctx->restart); } @@ -857,8 +855,8 @@ static int crypt_convert_block(struct crypt_config *cc, struct convert_context *ctx, struct ablkcipher_request *req) { - struct bio_vec *bv_in = bio_iovec_idx(ctx->bio_in, ctx->idx_in); - struct bio_vec *bv_out = bio_iovec_idx(ctx->bio_out, ctx->idx_out); + struct bio_vec bv_in = bio_iter_iovec(ctx->bio_in, ctx->iter_in); + struct bio_vec bv_out = bio_iter_iovec(ctx->bio_out, ctx->iter_out); struct dm_crypt_request *dmreq; u8 *iv; int r; @@ -869,24 +867,15 @@ static int crypt_convert_block(struct crypt_config *cc, dmreq->iv_sector = ctx->cc_sector; dmreq->ctx = ctx; sg_init_table(&dmreq->sg_in, 1); - sg_set_page(&dmreq->sg_in, bv_in->bv_page, 1 << SECTOR_SHIFT, - bv_in->bv_offset + ctx->offset_in); + sg_set_page(&dmreq->sg_in, bv_in.bv_page, 1 << SECTOR_SHIFT, + bv_in.bv_offset); sg_init_table(&dmreq->sg_out, 1); - sg_set_page(&dmreq->sg_out, bv_out->bv_page, 1 << SECTOR_SHIFT, - bv_out->bv_offset + ctx->offset_out); + sg_set_page(&dmreq->sg_out, bv_out.bv_page, 1 << SECTOR_SHIFT, + bv_out.bv_offset); - ctx->offset_in += 1 << SECTOR_SHIFT; - if (ctx->offset_in >= bv_in->bv_len) { - ctx->offset_in = 0; - ctx->idx_in++; - } - - ctx->offset_out += 1 << SECTOR_SHIFT; - if (ctx->offset_out >= bv_out->bv_len) { - ctx->offset_out = 0; - ctx->idx_out++; - } + bio_advance_iter(ctx->bio_in, &ctx->iter_in, 1 << SECTOR_SHIFT); + bio_advance_iter(ctx->bio_out, &ctx->iter_out, 1 << SECTOR_SHIFT); if (cc->iv_gen_ops) { r = cc->iv_gen_ops->generator(cc, iv, dmreq); @@ -937,8 +926,7 @@ static int crypt_convert(struct crypt_config *cc, atomic_set(&ctx->cc_pending, 1); - while(ctx->idx_in < ctx->bio_in->bi_vcnt && - ctx->idx_out < ctx->bio_out->bi_vcnt) { + while (ctx->iter_in.bi_size && ctx->iter_out.bi_size) { crypt_alloc_req(cc, ctx); @@ -1207,7 +1195,7 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async) } /* crypt_convert should have filled the clone bio */ - BUG_ON(io->ctx.idx_out < clone->bi_vcnt); + BUG_ON(io->ctx.iter_out.bi_size); clone->bi_iter.bi_sector = cc->start + io->sector; @@ -1246,7 +1234,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) } io->ctx.bio_out = clone; - io->ctx.idx_out = 0; + io->ctx.iter_out = clone->bi_iter; remaining -= clone->bi_iter.bi_size; sector += bio_sectors(clone); @@ -1290,8 +1278,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) crypt_inc_pending(new_io); crypt_convert_init(cc, &new_io->ctx, NULL, io->base_bio, sector); - new_io->ctx.idx_in = io->ctx.idx_in; - new_io->ctx.offset_in = io->ctx.offset_in; + new_io->ctx.iter_in = io->ctx.iter_in; /* * Fragments after the first use the base_io diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index 01558b093307..b2b8a10e8427 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -201,26 +201,29 @@ static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned offse /* * Functions for getting the pages from a bvec. */ -static void bvec_get_page(struct dpages *dp, +static void bio_get_page(struct dpages *dp, struct page **p, unsigned long *len, unsigned *offset) { - struct bio_vec *bvec = (struct bio_vec *) dp->context_ptr; - *p = bvec->bv_page; - *len = bvec->bv_len; - *offset = bvec->bv_offset; + struct bio *bio = dp->context_ptr; + struct bio_vec bvec = bio_iovec(bio); + *p = bvec.bv_page; + *len = bvec.bv_len; + *offset = bvec.bv_offset; } -static void bvec_next_page(struct dpages *dp) +static void bio_next_page(struct dpages *dp) { - struct bio_vec *bvec = (struct bio_vec *) dp->context_ptr; - dp->context_ptr = bvec + 1; + struct bio *bio = dp->context_ptr; + struct bio_vec bvec = bio_iovec(bio); + + bio_advance(bio, bvec.bv_len); } -static void bvec_dp_init(struct dpages *dp, struct bio_vec *bvec) +static void bio_dp_init(struct dpages *dp, struct bio *bio) { - dp->get_page = bvec_get_page; - dp->next_page = bvec_next_page; - dp->context_ptr = bvec; + dp->get_page = bio_get_page; + dp->next_page = bio_next_page; + dp->context_ptr = bio; } /* @@ -457,8 +460,8 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp, list_dp_init(dp, io_req->mem.ptr.pl, io_req->mem.offset); break; - case DM_IO_BVEC: - bvec_dp_init(dp, io_req->mem.ptr.bvec); + case DM_IO_BIO: + bio_dp_init(dp, io_req->mem.ptr.bio); break; case DM_IO_VMA: diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 9f6d8e6baa7d..f284e0bfb25f 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -526,8 +526,8 @@ static void read_async_bio(struct mirror *m, struct bio *bio) struct dm_io_region io; struct dm_io_request io_req = { .bi_rw = READ, - .mem.type = DM_IO_BVEC, - .mem.ptr.bvec = bio->bi_io_vec + bio->bi_iter.bi_idx, + .mem.type = DM_IO_BIO, + .mem.ptr.bio = bio, .notify.fn = read_callback, .notify.context = bio, .client = m->ms->io_client, @@ -629,8 +629,8 @@ static void do_write(struct mirror_set *ms, struct bio *bio) struct mirror *m; struct dm_io_request io_req = { .bi_rw = WRITE | (bio->bi_rw & WRITE_FLUSH_FUA), - .mem.type = DM_IO_BVEC, - .mem.ptr.bvec = bio->bi_io_vec + bio->bi_iter.bi_idx, + .mem.type = DM_IO_BIO, + .mem.ptr.bio = bio, .notify.fn = write_callback, .notify.context = bio, .client = ms->io_client, diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index 5392135924ca..ac35e959d49b 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -73,15 +73,10 @@ struct dm_verity_io { sector_t block; unsigned n_blocks; - /* saved bio vector */ - struct bio_vec *io_vec; - unsigned io_vec_size; + struct bvec_iter iter; struct work_struct work; - /* A space for short vectors; longer vectors are allocated separately. */ - struct bio_vec io_vec_inline[DM_VERITY_IO_VEC_INLINE]; - /* * Three variably-size fields follow this struct: * @@ -284,9 +279,10 @@ release_ret_r: static int verity_verify_io(struct dm_verity_io *io) { struct dm_verity *v = io->v; + struct bio *bio = dm_bio_from_per_bio_data(io, + v->ti->per_bio_data_size); unsigned b; int i; - unsigned vector = 0, offset = 0; for (b = 0; b < io->n_blocks; b++) { struct shash_desc *desc; @@ -336,31 +332,22 @@ test_block_hash: } todo = 1 << v->data_dev_block_bits; - do { - struct bio_vec *bv; + while (io->iter.bi_size) { u8 *page; - unsigned len; - - BUG_ON(vector >= io->io_vec_size); - bv = &io->io_vec[vector]; - page = kmap_atomic(bv->bv_page); - len = bv->bv_len - offset; - if (likely(len >= todo)) - len = todo; - r = crypto_shash_update(desc, - page + bv->bv_offset + offset, len); + struct bio_vec bv = bio_iter_iovec(bio, io->iter); + + page = kmap_atomic(bv.bv_page); + r = crypto_shash_update(desc, page + bv.bv_offset, + bv.bv_len); kunmap_atomic(page); + if (r < 0) { DMERR("crypto_shash_update failed: %d", r); return r; } - offset += len; - if (likely(offset == bv->bv_len)) { - offset = 0; - vector++; - } - todo -= len; - } while (todo); + + bio_advance_iter(bio, &io->iter, bv.bv_len); + } if (!v->version) { r = crypto_shash_update(desc, v->salt, v->salt_size); @@ -383,8 +370,6 @@ test_block_hash: return -EIO; } } - BUG_ON(vector != io->io_vec_size); - BUG_ON(offset); return 0; } @@ -400,9 +385,6 @@ static void verity_finish_io(struct dm_verity_io *io, int error) bio->bi_end_io = io->orig_bi_end_io; bio->bi_private = io->orig_bi_private; - if (io->io_vec != io->io_vec_inline) - mempool_free(io->io_vec, v->vec_mempool); - bio_endio(bio, error); } @@ -519,13 +501,7 @@ static int verity_map(struct dm_target *ti, struct bio *bio) bio->bi_end_io = verity_end_io; bio->bi_private = io; - io->io_vec_size = bio_segments(bio); - if (io->io_vec_size < DM_VERITY_IO_VEC_INLINE) - io->io_vec = io->io_vec_inline; - else - io->io_vec = mempool_alloc(v->vec_mempool, GFP_NOIO); - memcpy(io->io_vec, __bio_iovec(bio), - io->io_vec_size * sizeof(struct bio_vec)); + io->iter = bio->bi_iter; verity_submit_prefetch(v, io); diff --git a/fs/bio.c b/fs/bio.c index e32f2ffc3f33..a082ce2d197b 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -525,8 +525,17 @@ EXPORT_SYMBOL(bio_phys_segments); */ void __bio_clone(struct bio *bio, struct bio *bio_src) { - memcpy(bio->bi_io_vec, bio_src->bi_io_vec, - bio_src->bi_max_vecs * sizeof(struct bio_vec)); + if (bio_is_rw(bio_src)) { + struct bio_vec bv; + struct bvec_iter iter; + + bio_for_each_segment(bv, bio_src, iter) + bio->bi_io_vec[bio->bi_vcnt++] = bv; + } else if (bio_has_data(bio_src)) { + memcpy(bio->bi_io_vec, bio_src->bi_io_vec, + bio_src->bi_max_vecs * sizeof(struct bio_vec)); + bio->bi_vcnt = bio_src->bi_vcnt; + } /* * most users will be overriding ->bi_bdev with a new target, @@ -535,7 +544,6 @@ void __bio_clone(struct bio *bio, struct bio *bio_src) bio->bi_bdev = bio_src->bi_bdev; bio->bi_flags |= 1 << BIO_CLONED; bio->bi_rw = bio_src->bi_rw; - bio->bi_vcnt = bio_src->bi_vcnt; bio->bi_iter = bio_src->bi_iter; } EXPORT_SYMBOL(__bio_clone); diff --git a/include/linux/dm-io.h b/include/linux/dm-io.h index f4b0aa3126f5..a68cbe59e6ad 100644 --- a/include/linux/dm-io.h +++ b/include/linux/dm-io.h @@ -29,7 +29,7 @@ typedef void (*io_notify_fn)(unsigned long error, void *context); enum dm_io_mem_type { DM_IO_PAGE_LIST,/* Page list */ - DM_IO_BVEC, /* Bio vector */ + DM_IO_BIO, /* Bio vector */ DM_IO_VMA, /* Virtual memory area */ DM_IO_KMEM, /* Kernel memory */ }; @@ -41,7 +41,7 @@ struct dm_io_memory { union { struct page_list *pl; - struct bio_vec *bvec; + struct bio *bio; void *vma; void *addr; } ptr; -- cgit v1.2.3-59-g8ed1b From f38a5181d9f3e004b1f50f9d7e1f2a8492ce240a Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Wed, 7 Aug 2013 14:30:24 -0700 Subject: ceph: Convert to immutable biovecs Now that we've got a mechanism for immutable biovecs - bi_iter.bi_bvec_done - we need to convert drivers to use primitives that respect it instead of using the bvec array directly. Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: Sage Weil Cc: ceph-devel@vger.kernel.org --- include/linux/ceph/messenger.h | 4 ++-- net/ceph/messenger.c | 43 +++++++++++++++++------------------------- 2 files changed, 19 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 7c1420bb1dce..091fdb600d55 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -1,6 +1,7 @@ #ifndef __FS_CEPH_MESSENGER_H #define __FS_CEPH_MESSENGER_H +#include #include #include #include @@ -119,8 +120,7 @@ struct ceph_msg_data_cursor { #ifdef CONFIG_BLOCK struct { /* bio */ struct bio *bio; /* bio from list */ - unsigned int vector_index; /* vector from bio */ - unsigned int vector_offset; /* bytes from vector */ + struct bvec_iter bvec_iter; }; #endif /* CONFIG_BLOCK */ struct { /* pages */ diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 4a5df7b1cc9f..18c039b95c22 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -777,13 +777,12 @@ static void ceph_msg_data_bio_cursor_init(struct ceph_msg_data_cursor *cursor, bio = data->bio; BUG_ON(!bio); - BUG_ON(!bio->bi_vcnt); cursor->resid = min(length, data->bio_length); cursor->bio = bio; - cursor->vector_index = 0; - cursor->vector_offset = 0; - cursor->last_piece = length <= bio->bi_io_vec[0].bv_len; + cursor->bvec_iter = bio->bi_iter; + cursor->last_piece = + cursor->resid <= bio_iter_len(bio, cursor->bvec_iter); } static struct page *ceph_msg_data_bio_next(struct ceph_msg_data_cursor *cursor, @@ -792,71 +791,63 @@ static struct page *ceph_msg_data_bio_next(struct ceph_msg_data_cursor *cursor, { struct ceph_msg_data *data = cursor->data; struct bio *bio; - struct bio_vec *bio_vec; - unsigned int index; + struct bio_vec bio_vec; BUG_ON(data->type != CEPH_MSG_DATA_BIO); bio = cursor->bio; BUG_ON(!bio); - index = cursor->vector_index; - BUG_ON(index >= (unsigned int) bio->bi_vcnt); + bio_vec = bio_iter_iovec(bio, cursor->bvec_iter); - bio_vec = &bio->bi_io_vec[index]; - BUG_ON(cursor->vector_offset >= bio_vec->bv_len); - *page_offset = (size_t) (bio_vec->bv_offset + cursor->vector_offset); + *page_offset = (size_t) bio_vec.bv_offset; BUG_ON(*page_offset >= PAGE_SIZE); if (cursor->last_piece) /* pagelist offset is always 0 */ *length = cursor->resid; else - *length = (size_t) (bio_vec->bv_len - cursor->vector_offset); + *length = (size_t) bio_vec.bv_len; BUG_ON(*length > cursor->resid); BUG_ON(*page_offset + *length > PAGE_SIZE); - return bio_vec->bv_page; + return bio_vec.bv_page; } static bool ceph_msg_data_bio_advance(struct ceph_msg_data_cursor *cursor, size_t bytes) { struct bio *bio; - struct bio_vec *bio_vec; - unsigned int index; + struct bio_vec bio_vec; BUG_ON(cursor->data->type != CEPH_MSG_DATA_BIO); bio = cursor->bio; BUG_ON(!bio); - index = cursor->vector_index; - BUG_ON(index >= (unsigned int) bio->bi_vcnt); - bio_vec = &bio->bi_io_vec[index]; + bio_vec = bio_iter_iovec(bio, cursor->bvec_iter); /* Advance the cursor offset */ BUG_ON(cursor->resid < bytes); cursor->resid -= bytes; - cursor->vector_offset += bytes; - if (cursor->vector_offset < bio_vec->bv_len) + + bio_advance_iter(bio, &cursor->bvec_iter, bytes); + + if (bytes < bio_vec.bv_len) return false; /* more bytes to process in this segment */ - BUG_ON(cursor->vector_offset != bio_vec->bv_len); /* Move on to the next segment, and possibly the next bio */ - if (++index == (unsigned int) bio->bi_vcnt) { + if (!cursor->bvec_iter.bi_size) { bio = bio->bi_next; - index = 0; + cursor->bvec_iter = bio->bi_iter; } cursor->bio = bio; - cursor->vector_index = index; - cursor->vector_offset = 0; if (!cursor->last_piece) { BUG_ON(!cursor->resid); BUG_ON(!bio); /* A short read is OK, so use <= rather than == */ - if (cursor->resid <= bio->bi_io_vec[index].bv_len) + if (cursor->resid <= bio_iter_len(bio, cursor->bvec_iter)) cursor->last_piece = true; } -- cgit v1.2.3-59-g8ed1b From f619d25460473788944e3b71b030398681e8809b Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Wed, 7 Aug 2013 14:30:33 -0700 Subject: block: Kill bio_iovec_idx(), __bio_iovec() bio_iovec_idx() and __bio_iovec() don't have any valid uses anymore - previous users have been converted to bio_iovec_iter() or other methods. __BVEC_END() has to go too - the bvec array can't be used directly for the last biovec because we might only be using the first portion of it, we have to iterate over the bvec array with bio_for_each_segment() which checks against the current value of bi_iter.bi_size. Signed-off-by: Kent Overstreet Cc: Jens Axboe --- block/blk-merge.c | 13 +++++++++++-- include/linux/bio.h | 26 ++++++++------------------ 2 files changed, 19 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/block/blk-merge.c b/block/blk-merge.c index a1ead9049ed6..05c17be0eea4 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -86,6 +86,9 @@ EXPORT_SYMBOL(blk_recount_segments); static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio, struct bio *nxt) { + struct bio_vec end_bv, nxt_bv; + struct bvec_iter iter; + if (!blk_queue_cluster(q)) return 0; @@ -96,14 +99,20 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio, if (!bio_has_data(bio)) return 1; - if (!BIOVEC_PHYS_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt))) + bio_for_each_segment(end_bv, bio, iter) + if (end_bv.bv_len == iter.bi_size) + break; + + nxt_bv = bio_iovec(nxt); + + if (!BIOVEC_PHYS_MERGEABLE(&end_bv, &nxt_bv)) return 0; /* * bio and nxt are contiguous in memory; check if the queue allows * these two to be merged into one */ - if (BIO_SEG_BOUNDARY(q, bio, nxt)) + if (BIOVEC_SEG_BOUNDARY(q, &end_bv, &nxt_bv)) return 1; return 0; diff --git a/include/linux/bio.h b/include/linux/bio.h index aea9896a6289..1a31f9d9e057 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -61,9 +61,6 @@ * various member access, note that bio_data should of course not be used * on highmem page vectors */ -#define bio_iovec_idx(bio, idx) (&((bio)->bi_io_vec[(idx)])) -#define __bio_iovec(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) - #define __bvec_iter_bvec(bvec, iter) (&(bvec)[(iter).bi_idx]) #define bvec_iter_page(bvec, iter) \ @@ -162,19 +159,16 @@ static inline void *bio_data(struct bio *bio) * permanent PIO fall back, user is probably better off disabling highmem * I/O completely on that queue (see ide-dma for example) */ -#define __bio_kmap_atomic(bio, idx) \ - (kmap_atomic(bio_iovec_idx((bio), (idx))->bv_page) + \ - bio_iovec_idx((bio), (idx))->bv_offset) +#define __bio_kmap_atomic(bio, iter) \ + (kmap_atomic(bio_iter_iovec((bio), (iter)).bv_page) + \ + bio_iter_iovec((bio), (iter)).bv_offset) -#define __bio_kunmap_atomic(addr) kunmap_atomic(addr) +#define __bio_kunmap_atomic(addr) kunmap_atomic(addr) /* * merge helpers etc */ -#define __BVEC_END(bio) bio_iovec_idx((bio), (bio)->bi_vcnt - 1) -#define __BVEC_START(bio) bio_iovec_idx((bio), (bio)->bi_iter.bi_idx) - /* Default implementation of BIOVEC_PHYS_MERGEABLE */ #define __BIOVEC_PHYS_MERGEABLE(vec1, vec2) \ ((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2))) @@ -191,8 +185,6 @@ static inline void *bio_data(struct bio *bio) (((addr1) | (mask)) == (((addr2) - 1) | (mask))) #define BIOVEC_SEG_BOUNDARY(q, b1, b2) \ __BIO_SEG_BOUNDARY(bvec_to_phys((b1)), bvec_to_phys((b2)) + (b2)->bv_len, queue_segment_boundary((q))) -#define BIO_SEG_BOUNDARY(q, b1, b2) \ - BIOVEC_SEG_BOUNDARY((q), __BVEC_END((b1)), __BVEC_START((b2))) #define bio_io_error(bio) bio_endio((bio), -EIO) @@ -201,9 +193,7 @@ static inline void *bio_data(struct bio *bio) * before it got to the driver and the driver won't own all of it */ #define bio_for_each_segment_all(bvl, bio, i) \ - for (i = 0; \ - bvl = bio_iovec_idx((bio), (i)), i < (bio)->bi_vcnt; \ - i++) + for (i = 0, bvl = (bio)->bi_io_vec; i < (bio)->bi_vcnt; i++, bvl++) static inline void bvec_iter_advance(struct bio_vec *bv, struct bvec_iter *iter, unsigned bytes) @@ -468,15 +458,15 @@ static inline void bvec_kunmap_irq(char *buffer, unsigned long *flags) } #endif -static inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx, +static inline char *__bio_kmap_irq(struct bio *bio, struct bvec_iter iter, unsigned long *flags) { - return bvec_kmap_irq(bio_iovec_idx(bio, idx), flags); + return bvec_kmap_irq(&bio_iter_iovec(bio, iter), flags); } #define __bio_kunmap_irq(buf, flags) bvec_kunmap_irq(buf, flags) #define bio_kmap_irq(bio, flags) \ - __bio_kmap_irq((bio), (bio)->bi_iter.bi_idx, (flags)) + __bio_kmap_irq((bio), (bio)->bi_iter, (flags)) #define bio_kunmap_irq(buf,flags) __bio_kunmap_irq(buf, flags) /* -- cgit v1.2.3-59-g8ed1b From 59d276fe02d7e887a4825ef05c80b8f8c54ba60a Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sat, 23 Nov 2013 18:19:27 -0800 Subject: block: Add bio_clone_fast() bio_clone() just got more expensive - however, most users of bio_clone() don't actually need to modify the biovec. If they aren't modifying the biovec, and they can guarantee that the original bio isn't freed before the clone (also true in most cases), we can just point the clone at the original bio's biovec. Signed-off-by: Kent Overstreet --- drivers/md/bcache/request.c | 8 ++---- fs/bio.c | 60 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/bio.h | 2 ++ 3 files changed, 64 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 4c0a422fd49f..63451c724781 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -613,7 +613,6 @@ struct search { struct btree_op op; struct data_insert_op iop; - struct bio_vec bv[BIO_MAX_PAGES]; }; static void bch_cache_read_endio(struct bio *bio, int error) @@ -761,9 +760,7 @@ static void do_bio_hook(struct search *s) struct bio *bio = &s->bio.bio; bio_init(bio); - bio->bi_io_vec = s->bv; - bio->bi_max_vecs = BIO_MAX_PAGES; - __bio_clone(bio, s->orig_bio); + __bio_clone_fast(bio, s->orig_bio); bio->bi_end_io = request_endio; bio->bi_private = &s->cl; @@ -1065,8 +1062,7 @@ static void cached_dev_write(struct cached_dev *dc, struct search *s) closure_bio_submit(flush, cl, s->d); } } else { - s->iop.bio = bio_clone_bioset(bio, GFP_NOIO, - dc->disk.bio_split); + s->iop.bio = bio_clone_fast(bio, GFP_NOIO, dc->disk.bio_split); closure_bio_submit(bio, cl, s->d); } diff --git a/fs/bio.c b/fs/bio.c index 1628917e262a..00dc1893c6ee 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -548,6 +548,66 @@ void __bio_clone(struct bio *bio, struct bio *bio_src) } EXPORT_SYMBOL(__bio_clone); +/** + * __bio_clone_fast - clone a bio that shares the original bio's biovec + * @bio: destination bio + * @bio_src: bio to clone + * + * Clone a &bio. Caller will own the returned bio, but not + * the actual data it points to. Reference count of returned + * bio will be one. + * + * Caller must ensure that @bio_src is not freed before @bio. + */ +void __bio_clone_fast(struct bio *bio, struct bio *bio_src) +{ + BUG_ON(bio->bi_pool && BIO_POOL_IDX(bio) != BIO_POOL_NONE); + + /* + * most users will be overriding ->bi_bdev with a new target, + * so we don't set nor calculate new physical/hw segment counts here + */ + bio->bi_bdev = bio_src->bi_bdev; + bio->bi_flags |= 1 << BIO_CLONED; + bio->bi_rw = bio_src->bi_rw; + bio->bi_iter = bio_src->bi_iter; + bio->bi_io_vec = bio_src->bi_io_vec; +} +EXPORT_SYMBOL(__bio_clone_fast); + +/** + * bio_clone_fast - clone a bio that shares the original bio's biovec + * @bio: bio to clone + * @gfp_mask: allocation priority + * @bs: bio_set to allocate from + * + * Like __bio_clone_fast, only also allocates the returned bio + */ +struct bio *bio_clone_fast(struct bio *bio, gfp_t gfp_mask, struct bio_set *bs) +{ + struct bio *b; + + b = bio_alloc_bioset(gfp_mask, 0, bs); + if (!b) + return NULL; + + __bio_clone_fast(b, bio); + + if (bio_integrity(bio)) { + int ret; + + ret = bio_integrity_clone(b, bio, gfp_mask); + + if (ret < 0) { + bio_put(b); + return NULL; + } + } + + return b; +} +EXPORT_SYMBOL(bio_clone_fast); + /** * bio_clone_bioset - clone a bio * @bio_src: bio to clone diff --git a/include/linux/bio.h b/include/linux/bio.h index 1a31f9d9e057..1f83f4a3083e 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -328,6 +328,8 @@ extern mempool_t *biovec_create_pool(struct bio_set *bs, int pool_entries); extern struct bio *bio_alloc_bioset(gfp_t, int, struct bio_set *); extern void bio_put(struct bio *); +extern void __bio_clone_fast(struct bio *, struct bio *); +extern struct bio *bio_clone_fast(struct bio *, gfp_t, struct bio_set *); extern void __bio_clone(struct bio *, struct bio *); extern struct bio *bio_clone_bioset(struct bio *, gfp_t, struct bio_set *bs); -- cgit v1.2.3-59-g8ed1b From 1c3b13e64cf70d652fb04e32d13ae3e36810c2e4 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Tue, 29 Oct 2013 17:17:49 -0700 Subject: dm: Refactor for new bio cloning/splitting We need to convert the dm code to the new bvec_iter primitives which respect bi_bvec_done; they also allow us to drastically simplify dm's bio splitting code. Also, it's no longer necessary to save/restore the bvec array anymore - driver conversions for immutable bvecs are done, so drivers should never be modifying it. Also kill bio_sector_offset(), dm was the only user and it doesn't make much sense anymore. Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: Alasdair Kergon Cc: dm-devel@redhat.com Reviewed-by: Mike Snitzer --- drivers/md/dm-bio-record.h | 25 ------- drivers/md/dm.c | 174 ++++++--------------------------------------- fs/bio.c | 72 ------------------- include/linux/bio.h | 2 - 4 files changed, 20 insertions(+), 253 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/dm-bio-record.h b/drivers/md/dm-bio-record.h index 4f46e8e528de..dd3646111561 100644 --- a/drivers/md/dm-bio-record.h +++ b/drivers/md/dm-bio-record.h @@ -17,49 +17,24 @@ * original bio state. */ -struct dm_bio_vec_details { -#if PAGE_SIZE < 65536 - __u16 bv_len; - __u16 bv_offset; -#else - unsigned bv_len; - unsigned bv_offset; -#endif -}; - struct dm_bio_details { struct block_device *bi_bdev; unsigned long bi_flags; struct bvec_iter bi_iter; - struct dm_bio_vec_details bi_io_vec[BIO_MAX_PAGES]; }; static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio) { - unsigned i; - bd->bi_bdev = bio->bi_bdev; bd->bi_flags = bio->bi_flags; bd->bi_iter = bio->bi_iter; - - for (i = 0; i < bio->bi_vcnt; i++) { - bd->bi_io_vec[i].bv_len = bio->bi_io_vec[i].bv_len; - bd->bi_io_vec[i].bv_offset = bio->bi_io_vec[i].bv_offset; - } } static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio) { - unsigned i; - bio->bi_bdev = bd->bi_bdev; bio->bi_flags = bd->bi_flags; bio->bi_iter = bd->bi_iter; - - for (i = 0; i < bio->bi_vcnt; i++) { - bio->bi_io_vec[i].bv_len = bd->bi_io_vec[i].bv_len; - bio->bi_io_vec[i].bv_offset = bd->bi_io_vec[i].bv_offset; - } } #endif diff --git a/drivers/md/dm.c b/drivers/md/dm.c index ccd064ea4fe6..44a2fa6814ce 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1155,7 +1155,6 @@ struct clone_info { struct dm_io *io; sector_t sector; sector_t sector_count; - unsigned short idx; }; static void bio_setup_sector(struct bio *bio, sector_t sector, sector_t len) @@ -1164,68 +1163,24 @@ static void bio_setup_sector(struct bio *bio, sector_t sector, sector_t len) bio->bi_iter.bi_size = to_bytes(len); } -static void bio_setup_bv(struct bio *bio, unsigned short idx, unsigned short bv_count) -{ - bio->bi_iter.bi_idx = idx; - bio->bi_vcnt = idx + bv_count; - bio->bi_flags &= ~(1 << BIO_SEG_VALID); -} - -static void clone_bio_integrity(struct bio *bio, struct bio *clone, - unsigned short idx, unsigned len, unsigned offset, - unsigned trim) -{ - if (!bio_integrity(bio)) - return; - - bio_integrity_clone(clone, bio, GFP_NOIO); - - if (trim) - bio_integrity_trim(clone, bio_sector_offset(bio, idx, offset), len); -} - -/* - * Creates a little bio that just does part of a bvec. - */ -static void clone_split_bio(struct dm_target_io *tio, struct bio *bio, - sector_t sector, unsigned short idx, - unsigned offset, unsigned len) -{ - struct bio *clone = &tio->clone; - struct bio_vec *bv = bio->bi_io_vec + idx; - - *clone->bi_io_vec = *bv; - - bio_setup_sector(clone, sector, len); - - clone->bi_bdev = bio->bi_bdev; - clone->bi_rw = bio->bi_rw; - clone->bi_vcnt = 1; - clone->bi_io_vec->bv_offset = offset; - clone->bi_io_vec->bv_len = clone->bi_iter.bi_size; - clone->bi_flags |= 1 << BIO_CLONED; - - clone_bio_integrity(bio, clone, idx, len, offset, 1); -} - /* * Creates a bio that consists of range of complete bvecs. */ static void clone_bio(struct dm_target_io *tio, struct bio *bio, - sector_t sector, unsigned short idx, - unsigned short bv_count, unsigned len) + sector_t sector, unsigned len) { struct bio *clone = &tio->clone; - unsigned trim = 0; - __bio_clone(clone, bio); - bio_setup_sector(clone, sector, len); - bio_setup_bv(clone, idx, bv_count); + __bio_clone_fast(clone, bio); + + if (bio_integrity(bio)) + bio_integrity_clone(clone, bio, GFP_NOIO); + + bio_advance(clone, to_bytes(sector - clone->bi_iter.bi_sector)); + clone->bi_iter.bi_size = to_bytes(len); - if (idx != bio->bi_iter.bi_idx || - clone->bi_iter.bi_size < bio->bi_iter.bi_size) - trim = 1; - clone_bio_integrity(bio, clone, idx, len, 0, trim); + if (bio_integrity(bio)) + bio_integrity_trim(clone, 0, len); } static struct dm_target_io *alloc_tio(struct clone_info *ci, @@ -1258,7 +1213,7 @@ static void __clone_and_map_simple_bio(struct clone_info *ci, * ci->bio->bi_max_vecs is BIO_INLINE_VECS anyway, for both flush * and discard, so no need for concern about wasted bvec allocations. */ - __bio_clone(clone, ci->bio); + __bio_clone_fast(clone, ci->bio); if (len) bio_setup_sector(clone, ci->sector, len); @@ -1287,10 +1242,7 @@ static int __send_empty_flush(struct clone_info *ci) } static void __clone_and_map_data_bio(struct clone_info *ci, struct dm_target *ti, - sector_t sector, int nr_iovecs, - unsigned short idx, unsigned short bv_count, - unsigned offset, unsigned len, - unsigned split_bvec) + sector_t sector, unsigned len) { struct bio *bio = ci->bio; struct dm_target_io *tio; @@ -1304,11 +1256,8 @@ static void __clone_and_map_data_bio(struct clone_info *ci, struct dm_target *ti num_target_bios = ti->num_write_bios(ti, bio); for (target_bio_nr = 0; target_bio_nr < num_target_bios; target_bio_nr++) { - tio = alloc_tio(ci, ti, nr_iovecs, target_bio_nr); - if (split_bvec) - clone_split_bio(tio, bio, sector, idx, offset, len); - else - clone_bio(tio, bio, sector, idx, bv_count, len); + tio = alloc_tio(ci, ti, 0, target_bio_nr); + clone_bio(tio, bio, sector, len); __map_bio(tio); } } @@ -1379,60 +1328,6 @@ static int __send_write_same(struct clone_info *ci) return __send_changing_extent_only(ci, get_num_write_same_bios, NULL); } -/* - * Find maximum number of sectors / bvecs we can process with a single bio. - */ -static sector_t __len_within_target(struct clone_info *ci, sector_t max, int *idx) -{ - struct bio *bio = ci->bio; - sector_t bv_len, total_len = 0; - - for (*idx = ci->idx; max && (*idx < bio->bi_vcnt); (*idx)++) { - bv_len = to_sector(bio->bi_io_vec[*idx].bv_len); - - if (bv_len > max) - break; - - max -= bv_len; - total_len += bv_len; - } - - return total_len; -} - -static int __split_bvec_across_targets(struct clone_info *ci, - struct dm_target *ti, sector_t max) -{ - struct bio *bio = ci->bio; - struct bio_vec *bv = bio->bi_io_vec + ci->idx; - sector_t remaining = to_sector(bv->bv_len); - unsigned offset = 0; - sector_t len; - - do { - if (offset) { - ti = dm_table_find_target(ci->map, ci->sector); - if (!dm_target_is_valid(ti)) - return -EIO; - - max = max_io_len(ci->sector, ti); - } - - len = min(remaining, max); - - __clone_and_map_data_bio(ci, ti, ci->sector, 1, ci->idx, 0, - bv->bv_offset + offset, len, 1); - - ci->sector += len; - ci->sector_count -= len; - offset += to_bytes(len); - } while (remaining -= len); - - ci->idx++; - - return 0; -} - /* * Select the correct strategy for processing a non-flush bio. */ @@ -1440,8 +1335,7 @@ static int __split_and_process_non_flush(struct clone_info *ci) { struct bio *bio = ci->bio; struct dm_target *ti; - sector_t len, max; - int idx; + unsigned len; if (unlikely(bio->bi_rw & REQ_DISCARD)) return __send_discard(ci); @@ -1452,41 +1346,14 @@ static int __split_and_process_non_flush(struct clone_info *ci) if (!dm_target_is_valid(ti)) return -EIO; - max = max_io_len(ci->sector, ti); - - /* - * Optimise for the simple case where we can do all of - * the remaining io with a single clone. - */ - if (ci->sector_count <= max) { - __clone_and_map_data_bio(ci, ti, ci->sector, bio->bi_max_vecs, - ci->idx, bio->bi_vcnt - ci->idx, 0, - ci->sector_count, 0); - ci->sector_count = 0; - return 0; - } - - /* - * There are some bvecs that don't span targets. - * Do as many of these as possible. - */ - if (to_sector(bio->bi_io_vec[ci->idx].bv_len) <= max) { - len = __len_within_target(ci, max, &idx); - - __clone_and_map_data_bio(ci, ti, ci->sector, bio->bi_max_vecs, - ci->idx, idx - ci->idx, 0, len, 0); + len = min_t(sector_t, max_io_len(ci->sector, ti), ci->sector_count); - ci->sector += len; - ci->sector_count -= len; - ci->idx = idx; + __clone_and_map_data_bio(ci, ti, ci->sector, len); - return 0; - } + ci->sector += len; + ci->sector_count -= len; - /* - * Handle a bvec that must be split between two or more targets. - */ - return __split_bvec_across_targets(ci, ti, max); + return 0; } /* @@ -1512,7 +1379,6 @@ static void __split_and_process_bio(struct mapped_device *md, ci.io->md = md; spin_lock_init(&ci.io->endio_lock); ci.sector = bio->bi_iter.bi_sector; - ci.idx = bio->bi_iter.bi_idx; start_io_acct(ci.io); diff --git a/fs/bio.c b/fs/bio.c index 00dc1893c6ee..6e42b68ab0ac 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -514,40 +514,6 @@ inline int bio_phys_segments(struct request_queue *q, struct bio *bio) } EXPORT_SYMBOL(bio_phys_segments); -/** - * __bio_clone - clone a bio - * @bio: destination bio - * @bio_src: bio to clone - * - * Clone a &bio. Caller will own the returned bio, but not - * the actual data it points to. Reference count of returned - * bio will be one. - */ -void __bio_clone(struct bio *bio, struct bio *bio_src) -{ - if (bio_is_rw(bio_src)) { - struct bio_vec bv; - struct bvec_iter iter; - - bio_for_each_segment(bv, bio_src, iter) - bio->bi_io_vec[bio->bi_vcnt++] = bv; - } else if (bio_has_data(bio_src)) { - memcpy(bio->bi_io_vec, bio_src->bi_io_vec, - bio_src->bi_max_vecs * sizeof(struct bio_vec)); - bio->bi_vcnt = bio_src->bi_vcnt; - } - - /* - * most users will be overriding ->bi_bdev with a new target, - * so we don't set nor calculate new physical/hw segment counts here - */ - bio->bi_bdev = bio_src->bi_bdev; - bio->bi_flags |= 1 << BIO_CLONED; - bio->bi_rw = bio_src->bi_rw; - bio->bi_iter = bio_src->bi_iter; -} -EXPORT_SYMBOL(__bio_clone); - /** * __bio_clone_fast - clone a bio that shares the original bio's biovec * @bio: destination bio @@ -1921,44 +1887,6 @@ void bio_trim(struct bio *bio, int offset, int size) } EXPORT_SYMBOL_GPL(bio_trim); -/** - * bio_sector_offset - Find hardware sector offset in bio - * @bio: bio to inspect - * @index: bio_vec index - * @offset: offset in bv_page - * - * Return the number of hardware sectors between beginning of bio - * and an end point indicated by a bio_vec index and an offset - * within that vector's page. - */ -sector_t bio_sector_offset(struct bio *bio, unsigned short index, - unsigned int offset) -{ - unsigned int sector_sz; - struct bio_vec *bv; - sector_t sectors; - int i; - - sector_sz = queue_logical_block_size(bio->bi_bdev->bd_disk->queue); - sectors = 0; - - if (index >= bio->bi_iter.bi_idx) - index = bio->bi_vcnt - 1; - - bio_for_each_segment_all(bv, bio, i) { - if (i == index) { - if (offset > bv->bv_offset) - sectors += (offset - bv->bv_offset) / sector_sz; - break; - } - - sectors += bv->bv_len / sector_sz; - } - - return sectors; -} -EXPORT_SYMBOL(bio_sector_offset); - /* * create memory pools for biovec's in a bio_set. * use the global biovec slabs created for general use. diff --git a/include/linux/bio.h b/include/linux/bio.h index 1f83f4a3083e..0c32a45a419c 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -330,7 +330,6 @@ extern void bio_put(struct bio *); extern void __bio_clone_fast(struct bio *, struct bio *); extern struct bio *bio_clone_fast(struct bio *, gfp_t, struct bio_set *); -extern void __bio_clone(struct bio *, struct bio *); extern struct bio *bio_clone_bioset(struct bio *, gfp_t, struct bio_set *bs); extern struct bio_set *fs_bio_set; @@ -370,7 +369,6 @@ extern int bio_add_page(struct bio *, struct page *, unsigned int,unsigned int); extern int bio_add_pc_page(struct request_queue *, struct bio *, struct page *, unsigned int, unsigned int); extern int bio_get_nr_vecs(struct block_device *); -extern sector_t bio_sector_offset(struct bio *, unsigned short, unsigned int); extern struct bio *bio_map_user(struct request_queue *, struct block_device *, unsigned long, unsigned int, int, gfp_t); struct sg_iovec; -- cgit v1.2.3-59-g8ed1b From 196d38bccfcfa32faed8c561868336fdfa0fe8e4 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sat, 23 Nov 2013 18:34:15 -0800 Subject: block: Generic bio chaining This adds a generic mechanism for chaining bio completions. This is going to be used for a bio_split() replacement, and it turns out to be very useful in a fair amount of driver code - a fair number of drivers were implementing this in their own roundabout ways, often painfully. Note that this means it's no longer to call bio_endio() more than once on the same bio! This can cause problems for drivers that save/restore bi_end_io. Arguably they shouldn't be saving/restoring bi_end_io at all - in all but the simplest cases they'd be better off just cloning the bio, and immutable biovecs is making bio cloning cheaper. But for now, we add a bio_endio_nodec() for these cases. Signed-off-by: Kent Overstreet Cc: Jens Axboe --- drivers/md/bcache/io.c | 2 +- drivers/md/dm-cache-target.c | 6 ++++ drivers/md/dm-snap.c | 1 + drivers/md/dm-thin.c | 8 +++-- drivers/md/dm-verity.c | 2 +- fs/bio-integrity.c | 2 +- fs/bio.c | 76 ++++++++++++++++++++++++++++++++++++++++---- include/linux/bio.h | 2 ++ include/linux/blk_types.h | 2 ++ 9 files changed, 90 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index 0f0ab659914d..522f95778443 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -133,7 +133,7 @@ static void bch_bio_submit_split_done(struct closure *cl) s->bio->bi_end_io = s->bi_end_io; s->bio->bi_private = s->bi_private; - bio_endio(s->bio, 0); + bio_endio_nodec(s->bio, 0); closure_debug_destroy(&s->cl); mempool_free(s, s->p->bio_split_hook); diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 86f9c83eb30c..bf3a206abd78 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -765,6 +765,12 @@ static void writethrough_endio(struct bio *bio, int err) dm_unhook_bio(&pb->hook_info, bio); + /* + * Must bump bi_remaining to allow bio to complete with + * restored bi_end_io. + */ + atomic_inc(&bio->bi_remaining); + if (err) { bio_endio(bio, err); return; diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 3ded8c729dfb..80b5cabbea29 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c @@ -1415,6 +1415,7 @@ out: if (full_bio) { full_bio->bi_end_io = pe->full_bio_end_io; full_bio->bi_private = pe->full_bio_private; + atomic_inc(&full_bio->bi_remaining); } free_pending_exception(pe); diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index a65402480c8c..1abb4a24c338 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -611,8 +611,10 @@ static void cell_defer_no_holder(struct thin_c *tc, struct dm_bio_prison_cell *c static void process_prepared_mapping_fail(struct dm_thin_new_mapping *m) { - if (m->bio) + if (m->bio) { m->bio->bi_end_io = m->saved_bi_end_io; + atomic_inc(&m->bio->bi_remaining); + } cell_error(m->tc->pool, m->cell); list_del(&m->list); mempool_free(m, m->tc->pool->mapping_pool); @@ -626,8 +628,10 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m) int r; bio = m->bio; - if (bio) + if (bio) { bio->bi_end_io = m->saved_bi_end_io; + atomic_inc(&bio->bi_remaining); + } if (m->err) { cell_error(pool, m->cell); diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity.c index ac35e959d49b..796007a5e0e1 100644 --- a/drivers/md/dm-verity.c +++ b/drivers/md/dm-verity.c @@ -385,7 +385,7 @@ static void verity_finish_io(struct dm_verity_io *io, int error) bio->bi_end_io = io->orig_bi_end_io; bio->bi_private = io->orig_bi_private; - bio_endio(bio, error); + bio_endio_nodec(bio, error); } static void verity_work(struct work_struct *w) diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index fed744b8c9e5..9d547d2e357c 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c @@ -502,7 +502,7 @@ static void bio_integrity_verify_fn(struct work_struct *work) /* Restore original bio completion handler */ bio->bi_end_io = bip->bip_end_io; - bio_endio(bio, error); + bio_endio_nodec(bio, error); } /** diff --git a/fs/bio.c b/fs/bio.c index e6dfa06773ac..b0a16dbc71ef 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -273,6 +273,7 @@ void bio_init(struct bio *bio) { memset(bio, 0, sizeof(*bio)); bio->bi_flags = 1 << BIO_UPTODATE; + atomic_set(&bio->bi_remaining, 1); atomic_set(&bio->bi_cnt, 1); } EXPORT_SYMBOL(bio_init); @@ -295,9 +296,35 @@ void bio_reset(struct bio *bio) memset(bio, 0, BIO_RESET_BYTES); bio->bi_flags = flags|(1 << BIO_UPTODATE); + atomic_set(&bio->bi_remaining, 1); } EXPORT_SYMBOL(bio_reset); +static void bio_chain_endio(struct bio *bio, int error) +{ + bio_endio(bio->bi_private, error); + bio_put(bio); +} + +/** + * bio_chain - chain bio completions + * + * The caller won't have a bi_end_io called when @bio completes - instead, + * @parent's bi_end_io won't be called until both @parent and @bio have + * completed; the chained bio will also be freed when it completes. + * + * The caller must not set bi_private or bi_end_io in @bio. + */ +void bio_chain(struct bio *bio, struct bio *parent) +{ + BUG_ON(bio->bi_private || bio->bi_end_io); + + bio->bi_private = parent; + bio->bi_end_io = bio_chain_endio; + atomic_inc(&parent->bi_remaining); +} +EXPORT_SYMBOL(bio_chain); + static void bio_alloc_rescue(struct work_struct *work) { struct bio_set *bs = container_of(work, struct bio_set, rescue_work); @@ -1719,16 +1746,53 @@ EXPORT_SYMBOL(bio_flush_dcache_pages); **/ void bio_endio(struct bio *bio, int error) { - if (error) - clear_bit(BIO_UPTODATE, &bio->bi_flags); - else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) - error = -EIO; + while (bio) { + BUG_ON(atomic_read(&bio->bi_remaining) <= 0); + + if (error) + clear_bit(BIO_UPTODATE, &bio->bi_flags); + else if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) + error = -EIO; + + if (!atomic_dec_and_test(&bio->bi_remaining)) + return; - if (bio->bi_end_io) - bio->bi_end_io(bio, error); + /* + * Need to have a real endio function for chained bios, + * otherwise various corner cases will break (like stacking + * block devices that save/restore bi_end_io) - however, we want + * to avoid unbounded recursion and blowing the stack. Tail call + * optimization would handle this, but compiling with frame + * pointers also disables gcc's sibling call optimization. + */ + if (bio->bi_end_io == bio_chain_endio) { + struct bio *parent = bio->bi_private; + bio_put(bio); + bio = parent; + } else { + if (bio->bi_end_io) + bio->bi_end_io(bio, error); + bio = NULL; + } + } } EXPORT_SYMBOL(bio_endio); +/** + * bio_endio_nodec - end I/O on a bio, without decrementing bi_remaining + * @bio: bio + * @error: error, if any + * + * For code that has saved and restored bi_end_io; thing hard before using this + * function, probably you should've cloned the entire bio. + **/ +void bio_endio_nodec(struct bio *bio, int error) +{ + atomic_inc(&bio->bi_remaining); + bio_endio(bio, error); +} +EXPORT_SYMBOL(bio_endio_nodec); + void bio_pair_release(struct bio_pair *bp) { if (atomic_dec_and_test(&bp->cnt)) { diff --git a/include/linux/bio.h b/include/linux/bio.h index 0c32a45a419c..64f5169c224b 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -356,6 +356,7 @@ static inline struct bio *bio_clone_kmalloc(struct bio *bio, gfp_t gfp_mask) } extern void bio_endio(struct bio *, int); +extern void bio_endio_nodec(struct bio *, int); struct request_queue; extern int bio_phys_segments(struct request_queue *, struct bio *); @@ -364,6 +365,7 @@ extern void bio_advance(struct bio *, unsigned); extern void bio_init(struct bio *); extern void bio_reset(struct bio *); +void bio_chain(struct bio *, struct bio *); extern int bio_add_page(struct bio *, struct page *, unsigned int,unsigned int); extern int bio_add_pc_page(struct request_queue *, struct bio *, struct page *, diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index d369f8f6af79..bbc3a6c88fce 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -65,6 +65,8 @@ struct bio { unsigned int bi_seg_front_size; unsigned int bi_seg_back_size; + atomic_t bi_remaining; + bio_end_io_t *bi_end_io; void *bi_private; -- cgit v1.2.3-59-g8ed1b From ee67891bf132612feb7b999ee1f3350b40867cb4 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Wed, 7 Aug 2013 14:32:45 -0700 Subject: block: Rename bio_split() -> bio_pair_split() This is prep work for introducing a more general bio_split(). Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: NeilBrown Cc: Alasdair Kergon Cc: Lars Ellenberg Cc: Peter Osterlund Cc: Sage Weil --- drivers/block/pktcdvd.c | 2 +- drivers/md/linear.c | 2 +- drivers/md/raid0.c | 6 +++--- drivers/md/raid10.c | 2 +- fs/bio.c | 4 ++-- include/linux/bio.h | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index ce986bacf7b7..28789b82ae7d 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2399,7 +2399,7 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) if (last_zone != zone) { BUG_ON(last_zone != zone + pd->settings.size); first_sectors = last_zone - bio->bi_iter.bi_sector; - bp = bio_split(bio, first_sectors); + bp = bio_pair_split(bio, first_sectors); BUG_ON(!bp); pkt_make_request(q, &bp->bio1); pkt_make_request(q, &bp->bio2); diff --git a/drivers/md/linear.c b/drivers/md/linear.c index fb3b0d04edfb..e9b53e9793bf 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -326,7 +326,7 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio) rcu_read_unlock(); - bp = bio_split(bio, end_sector - bio->bi_iter.bi_sector); + bp = bio_pair_split(bio, end_sector - bio->bi_iter.bi_sector); linear_make_request(mddev, &bp->bio1); linear_make_request(mddev, &bp->bio2); diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 8ee1a6c658b4..ea754dd1a5f5 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -534,11 +534,11 @@ static void raid0_make_request(struct mddev *mddev, struct bio *bio) * refuse to split for us, so we need to split it. */ if (likely(is_power_of_2(chunk_sects))) - bp = bio_split(bio, chunk_sects - (sector & + bp = bio_pair_split(bio, chunk_sects - (sector & (chunk_sects-1))); else - bp = bio_split(bio, chunk_sects - - sector_div(sector, chunk_sects)); + bp = bio_pair_split(bio, chunk_sects - + sector_div(sector, chunk_sects)); raid0_make_request(mddev, &bp->bio1); raid0_make_request(mddev, &bp->bio2); bio_pair_release(bp); diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index ac4bfa438c57..69c1bc8da88f 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1193,7 +1193,7 @@ static void make_request(struct mddev *mddev, struct bio * bio) /* This is a one page bio that upper layers * refuse to split for us, so we need to split it. */ - bp = bio_split(bio, chunk_sects - + bp = bio_pair_split(bio, chunk_sects - (bio->bi_iter.bi_sector & (chunk_sects - 1))); /* Each of these 'make_request' calls will call 'wait_barrier'. diff --git a/fs/bio.c b/fs/bio.c index b0a16dbc71ef..a3e753f4d5a6 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -1827,7 +1827,7 @@ static void bio_pair_end_2(struct bio *bi, int err) /* * split a bio - only worry about a bio with a single page in its iovec */ -struct bio_pair *bio_split(struct bio *bi, int first_sectors) +struct bio_pair *bio_pair_split(struct bio *bi, int first_sectors) { struct bio_pair *bp = mempool_alloc(bio_split_pool, GFP_NOIO); @@ -1874,7 +1874,7 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors) return bp; } -EXPORT_SYMBOL(bio_split); +EXPORT_SYMBOL(bio_pair_split); /** * bio_trim - trim a bio diff --git a/include/linux/bio.h b/include/linux/bio.h index 64f5169c224b..aa67af0b31ac 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -317,7 +317,7 @@ struct bio_pair { atomic_t cnt; int error; }; -extern struct bio_pair *bio_split(struct bio *bi, int first_sectors); +extern struct bio_pair *bio_pair_split(struct bio *bi, int first_sectors); extern void bio_pair_release(struct bio_pair *dbio); extern void bio_trim(struct bio *bio, int offset, int size); -- cgit v1.2.3-59-g8ed1b From 20d0189b1012a37d2533a87fb451f7852f2418d1 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sat, 23 Nov 2013 18:21:01 -0800 Subject: block: Introduce new bio_split() The new bio_split() can split arbitrary bios - it's not restricted to single page bios, like the old bio_split() (previously renamed to bio_pair_split()). It also has different semantics - it doesn't allocate a struct bio_pair, leaving it up to the caller to handle completions. Then convert the existing bio_pair_split() users to the new bio_split() - and also nvme, which was open coding bio splitting. (We have to take that BUG_ON() out of bio_integrity_trim() because this bio_split() needs to use it, and there's no reason it has to be used on bios marked as cloned; BIO_CLONED doesn't seem to have clearly documented semantics anyways.) Signed-off-by: Kent Overstreet Cc: Jens Axboe Cc: Martin K. Petersen Cc: Matthew Wilcox Cc: Keith Busch Cc: Vishal Verma Cc: Jiri Kosina Cc: Neil Brown --- drivers/block/nvme-core.c | 106 +++------------------------------- drivers/block/pktcdvd.c | 136 ++++++++++++++++++++++++-------------------- drivers/md/bcache/bcache.h | 1 - drivers/md/bcache/io.c | 82 +------------------------- drivers/md/bcache/request.c | 12 ++-- drivers/md/linear.c | 96 +++++++++++++++---------------- drivers/md/raid0.c | 77 +++++++++---------------- drivers/md/raid10.c | 113 +++++++++++++++--------------------- fs/bio.c | 36 ++++++++++++ include/linux/bio.h | 22 +++++++ 10 files changed, 272 insertions(+), 409 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 5539d2920872..1f14ac403945 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -441,104 +441,19 @@ int nvme_setup_prps(struct nvme_dev *dev, struct nvme_common_command *cmd, return total_len; } -struct nvme_bio_pair { - struct bio b1, b2, *parent; - struct bio_vec *bv1, *bv2; - int err; - atomic_t cnt; -}; - -static void nvme_bio_pair_endio(struct bio *bio, int err) -{ - struct nvme_bio_pair *bp = bio->bi_private; - - if (err) - bp->err = err; - - if (atomic_dec_and_test(&bp->cnt)) { - bio_endio(bp->parent, bp->err); - kfree(bp->bv1); - kfree(bp->bv2); - kfree(bp); - } -} - -static struct nvme_bio_pair *nvme_bio_split(struct bio *bio, int idx, - int len, int offset) -{ - struct nvme_bio_pair *bp; - - BUG_ON(len > bio->bi_iter.bi_size); - BUG_ON(idx > bio->bi_vcnt); - - bp = kmalloc(sizeof(*bp), GFP_ATOMIC); - if (!bp) - return NULL; - bp->err = 0; - - bp->b1 = *bio; - bp->b2 = *bio; - - bp->b1.bi_iter.bi_size = len; - bp->b2.bi_iter.bi_size -= len; - bp->b1.bi_vcnt = idx; - bp->b2.bi_iter.bi_idx = idx; - bp->b2.bi_iter.bi_sector += len >> 9; - - if (offset) { - bp->bv1 = kmalloc(bio->bi_max_vecs * sizeof(struct bio_vec), - GFP_ATOMIC); - if (!bp->bv1) - goto split_fail_1; - - bp->bv2 = kmalloc(bio->bi_max_vecs * sizeof(struct bio_vec), - GFP_ATOMIC); - if (!bp->bv2) - goto split_fail_2; - - memcpy(bp->bv1, bio->bi_io_vec, - bio->bi_max_vecs * sizeof(struct bio_vec)); - memcpy(bp->bv2, bio->bi_io_vec, - bio->bi_max_vecs * sizeof(struct bio_vec)); - - bp->b1.bi_io_vec = bp->bv1; - bp->b2.bi_io_vec = bp->bv2; - bp->b2.bi_io_vec[idx].bv_offset += offset; - bp->b2.bi_io_vec[idx].bv_len -= offset; - bp->b1.bi_io_vec[idx].bv_len = offset; - bp->b1.bi_vcnt++; - } else - bp->bv1 = bp->bv2 = NULL; - - bp->b1.bi_private = bp; - bp->b2.bi_private = bp; - - bp->b1.bi_end_io = nvme_bio_pair_endio; - bp->b2.bi_end_io = nvme_bio_pair_endio; - - bp->parent = bio; - atomic_set(&bp->cnt, 2); - - return bp; - - split_fail_2: - kfree(bp->bv1); - split_fail_1: - kfree(bp); - return NULL; -} - static int nvme_split_and_submit(struct bio *bio, struct nvme_queue *nvmeq, - int idx, int len, int offset) + int len) { - struct nvme_bio_pair *bp = nvme_bio_split(bio, idx, len, offset); - if (!bp) + struct bio *split = bio_split(bio, len >> 9, GFP_ATOMIC, NULL); + if (!split) return -ENOMEM; + bio_chain(split, bio); + if (bio_list_empty(&nvmeq->sq_cong)) add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait); - bio_list_add(&nvmeq->sq_cong, &bp->b1); - bio_list_add(&nvmeq->sq_cong, &bp->b2); + bio_list_add(&nvmeq->sq_cong, split); + bio_list_add(&nvmeq->sq_cong, bio); return 0; } @@ -568,8 +483,7 @@ static int nvme_map_bio(struct nvme_queue *nvmeq, struct nvme_iod *iod, } else { if (!first && BIOVEC_NOT_VIRT_MERGEABLE(&bvprv, &bvec)) return nvme_split_and_submit(bio, nvmeq, - iter.bi_idx, - length, 0); + length); sg = sg ? sg + 1 : iod->sg; sg_set_page(sg, bvec.bv_page, @@ -578,9 +492,7 @@ static int nvme_map_bio(struct nvme_queue *nvmeq, struct nvme_iod *iod, } if (split_len - length < bvec.bv_len) - return nvme_split_and_submit(bio, nvmeq, iter.bi_idx, - split_len, - split_len - length); + return nvme_split_and_submit(bio, nvmeq, split_len); length += bvec.bv_len; bvprv = bvec; first = 0; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 28789b82ae7d..3dda09a5ec41 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2338,75 +2338,29 @@ static void pkt_end_io_read_cloned(struct bio *bio, int err) pkt_bio_finished(pd); } -static void pkt_make_request(struct request_queue *q, struct bio *bio) +static void pkt_make_request_read(struct pktcdvd_device *pd, struct bio *bio) { - struct pktcdvd_device *pd; - char b[BDEVNAME_SIZE]; + struct bio *cloned_bio = bio_clone(bio, GFP_NOIO); + struct packet_stacked_data *psd = mempool_alloc(psd_pool, GFP_NOIO); + + psd->pd = pd; + psd->bio = bio; + cloned_bio->bi_bdev = pd->bdev; + cloned_bio->bi_private = psd; + cloned_bio->bi_end_io = pkt_end_io_read_cloned; + pd->stats.secs_r += bio_sectors(bio); + pkt_queue_bio(pd, cloned_bio); +} + +static void pkt_make_request_write(struct request_queue *q, struct bio *bio) +{ + struct pktcdvd_device *pd = q->queuedata; sector_t zone; struct packet_data *pkt; int was_empty, blocked_bio; struct pkt_rb_node *node; - pd = q->queuedata; - if (!pd) { - pr_err("%s incorrect request queue\n", - bdevname(bio->bi_bdev, b)); - goto end_io; - } - - /* - * Clone READ bios so we can have our own bi_end_io callback. - */ - if (bio_data_dir(bio) == READ) { - struct bio *cloned_bio = bio_clone(bio, GFP_NOIO); - struct packet_stacked_data *psd = mempool_alloc(psd_pool, GFP_NOIO); - - psd->pd = pd; - psd->bio = bio; - cloned_bio->bi_bdev = pd->bdev; - cloned_bio->bi_private = psd; - cloned_bio->bi_end_io = pkt_end_io_read_cloned; - pd->stats.secs_r += bio_sectors(bio); - pkt_queue_bio(pd, cloned_bio); - return; - } - - if (!test_bit(PACKET_WRITABLE, &pd->flags)) { - pkt_notice(pd, "WRITE for ro device (%llu)\n", - (unsigned long long)bio->bi_iter.bi_sector); - goto end_io; - } - - if (!bio->bi_iter.bi_size || (bio->bi_iter.bi_size % CD_FRAMESIZE)) { - pkt_err(pd, "wrong bio size\n"); - goto end_io; - } - - blk_queue_bounce(q, &bio); - zone = get_zone(bio->bi_iter.bi_sector, pd); - pkt_dbg(2, pd, "start = %6llx stop = %6llx\n", - (unsigned long long)bio->bi_iter.bi_sector, - (unsigned long long)bio_end_sector(bio)); - - /* Check if we have to split the bio */ - { - struct bio_pair *bp; - sector_t last_zone; - int first_sectors; - - last_zone = get_zone(bio_end_sector(bio) - 1, pd); - if (last_zone != zone) { - BUG_ON(last_zone != zone + pd->settings.size); - first_sectors = last_zone - bio->bi_iter.bi_sector; - bp = bio_pair_split(bio, first_sectors); - BUG_ON(!bp); - pkt_make_request(q, &bp->bio1); - pkt_make_request(q, &bp->bio2); - bio_pair_release(bp); - return; - } - } /* * If we find a matching packet in state WAITING or READ_WAIT, we can @@ -2480,6 +2434,64 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio) */ wake_up(&pd->wqueue); } +} + +static void pkt_make_request(struct request_queue *q, struct bio *bio) +{ + struct pktcdvd_device *pd; + char b[BDEVNAME_SIZE]; + struct bio *split; + + pd = q->queuedata; + if (!pd) { + pr_err("%s incorrect request queue\n", + bdevname(bio->bi_bdev, b)); + goto end_io; + } + + pkt_dbg(2, pd, "start = %6llx stop = %6llx\n", + (unsigned long long)bio->bi_iter.bi_sector, + (unsigned long long)bio_end_sector(bio)); + + /* + * Clone READ bios so we can have our own bi_end_io callback. + */ + if (bio_data_dir(bio) == READ) { + pkt_make_request_read(pd, bio); + return; + } + + if (!test_bit(PACKET_WRITABLE, &pd->flags)) { + pkt_notice(pd, "WRITE for ro device (%llu)\n", + (unsigned long long)bio->bi_iter.bi_sector); + goto end_io; + } + + if (!bio->bi_iter.bi_size || (bio->bi_iter.bi_size % CD_FRAMESIZE)) { + pkt_err(pd, "wrong bio size\n"); + goto end_io; + } + + blk_queue_bounce(q, &bio); + + do { + sector_t zone = get_zone(bio->bi_iter.bi_sector, pd); + sector_t last_zone = get_zone(bio_end_sector(bio) - 1, pd); + + if (last_zone != zone) { + BUG_ON(last_zone != zone + pd->settings.size); + + split = bio_split(bio, last_zone - + bio->bi_iter.bi_sector, + GFP_NOIO, fs_bio_set); + bio_chain(split, bio); + } else { + split = bio; + } + + pkt_make_request_write(q, split); + } while (split != bio); + return; end_io: bio_io_error(bio); diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 6b6fe935be73..964353c5329d 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -901,7 +901,6 @@ void bch_bbio_endio(struct cache_set *, struct bio *, int, const char *); void bch_bbio_free(struct bio *, struct cache_set *); struct bio *bch_bbio_alloc(struct cache_set *); -struct bio *bch_bio_split(struct bio *, int, gfp_t, struct bio_set *); void bch_generic_make_request(struct bio *, struct bio_split_pool *); void __bch_submit_bbio(struct bio *, struct cache_set *); void bch_submit_bbio(struct bio *, struct cache_set *, struct bkey *, unsigned); diff --git a/drivers/md/bcache/io.c b/drivers/md/bcache/io.c index 522f95778443..fa028fa82df4 100644 --- a/drivers/md/bcache/io.c +++ b/drivers/md/bcache/io.c @@ -11,84 +11,6 @@ #include -/** - * bch_bio_split - split a bio - * @bio: bio to split - * @sectors: number of sectors to split from the front of @bio - * @gfp: gfp mask - * @bs: bio set to allocate from - * - * Allocates and returns a new bio which represents @sectors from the start of - * @bio, and updates @bio to represent the remaining sectors. - * - * If bio_sectors(@bio) was less than or equal to @sectors, returns @bio - * unchanged. - * - * The newly allocated bio will point to @bio's bi_io_vec, if the split was on a - * bvec boundry; it is the caller's responsibility to ensure that @bio is not - * freed before the split. - */ -struct bio *bch_bio_split(struct bio *bio, int sectors, - gfp_t gfp, struct bio_set *bs) -{ - unsigned vcnt = 0, nbytes = sectors << 9; - struct bio_vec bv; - struct bvec_iter iter; - struct bio *ret = NULL; - - BUG_ON(sectors <= 0); - - if (sectors >= bio_sectors(bio)) - return bio; - - if (bio->bi_rw & REQ_DISCARD) { - ret = bio_alloc_bioset(gfp, 1, bs); - if (!ret) - return NULL; - goto out; - } - - bio_for_each_segment(bv, bio, iter) { - vcnt++; - - if (nbytes <= bv.bv_len) - break; - - nbytes -= bv.bv_len; - } - - ret = bio_alloc_bioset(gfp, vcnt, bs); - if (!ret) - return NULL; - - bio_for_each_segment(bv, bio, iter) { - ret->bi_io_vec[ret->bi_vcnt++] = bv; - - if (ret->bi_vcnt == vcnt) - break; - } - - ret->bi_io_vec[ret->bi_vcnt - 1].bv_len = nbytes; -out: - ret->bi_bdev = bio->bi_bdev; - ret->bi_iter.bi_sector = bio->bi_iter.bi_sector; - ret->bi_iter.bi_size = sectors << 9; - ret->bi_rw = bio->bi_rw; - - if (bio_integrity(bio)) { - if (bio_integrity_clone(ret, bio, gfp)) { - bio_put(ret); - return NULL; - } - - bio_integrity_trim(ret, 0, bio_sectors(ret)); - } - - bio_advance(bio, ret->bi_iter.bi_size); - - return ret; -} - static unsigned bch_bio_max_sectors(struct bio *bio) { struct request_queue *q = bdev_get_queue(bio->bi_bdev); @@ -172,8 +94,8 @@ void bch_generic_make_request(struct bio *bio, struct bio_split_pool *p) bio_get(bio); do { - n = bch_bio_split(bio, bch_bio_max_sectors(bio), - GFP_NOIO, s->p->bio_split); + n = bio_next_split(bio, bch_bio_max_sectors(bio), + GFP_NOIO, s->p->bio_split); n->bi_end_io = bch_bio_submit_split_endio; n->bi_private = &s->cl; diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 63451c724781..5878cdb39529 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -371,7 +371,7 @@ static void bch_data_insert_start(struct closure *cl) op->writeback)) goto err; - n = bch_bio_split(bio, KEY_SIZE(k), GFP_NOIO, split); + n = bio_next_split(bio, KEY_SIZE(k), GFP_NOIO, split); n->bi_end_io = bch_data_insert_endio; n->bi_private = cl; @@ -679,9 +679,9 @@ static int cache_lookup_fn(struct btree_op *op, struct btree *b, struct bkey *k) if (KEY_DIRTY(k)) s->read_dirty_data = true; - n = bch_bio_split(bio, min_t(uint64_t, INT_MAX, - KEY_OFFSET(k) - bio->bi_iter.bi_sector), - GFP_NOIO, s->d->bio_split); + n = bio_next_split(bio, min_t(uint64_t, INT_MAX, + KEY_OFFSET(k) - bio->bi_iter.bi_sector), + GFP_NOIO, s->d->bio_split); bio_key = &container_of(n, struct bbio, bio)->key; bch_bkey_copy_single_ptr(bio_key, k, ptr); @@ -920,7 +920,7 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s, struct bio *miss, *cache_bio; if (s->cache_miss || s->iop.bypass) { - miss = bch_bio_split(bio, sectors, GFP_NOIO, s->d->bio_split); + miss = bio_next_split(bio, sectors, GFP_NOIO, s->d->bio_split); ret = miss == bio ? MAP_DONE : MAP_CONTINUE; goto out_submit; } @@ -943,7 +943,7 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s, s->iop.replace = true; - miss = bch_bio_split(bio, sectors, GFP_NOIO, s->d->bio_split); + miss = bio_next_split(bio, sectors, GFP_NOIO, s->d->bio_split); /* btree_search_recurse()'s btree iterator is no good anymore */ ret = miss == bio ? MAP_DONE : -EINTR; diff --git a/drivers/md/linear.c b/drivers/md/linear.c index e9b53e9793bf..56f534b4a2d2 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -288,65 +288,65 @@ static int linear_stop (struct mddev *mddev) static void linear_make_request(struct mddev *mddev, struct bio *bio) { + char b[BDEVNAME_SIZE]; struct dev_info *tmp_dev; - sector_t start_sector; + struct bio *split; + sector_t start_sector, end_sector, data_offset; if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); return; } - rcu_read_lock(); - tmp_dev = which_dev(mddev, bio->bi_iter.bi_sector); - start_sector = tmp_dev->end_sector - tmp_dev->rdev->sectors; - - - if (unlikely(bio->bi_iter.bi_sector >= (tmp_dev->end_sector) - || (bio->bi_iter.bi_sector < start_sector))) { - char b[BDEVNAME_SIZE]; - - printk(KERN_ERR - "md/linear:%s: make_request: Sector %llu out of bounds on " - "dev %s: %llu sectors, offset %llu\n", - mdname(mddev), - (unsigned long long)bio->bi_iter.bi_sector, - bdevname(tmp_dev->rdev->bdev, b), - (unsigned long long)tmp_dev->rdev->sectors, - (unsigned long long)start_sector); - rcu_read_unlock(); - bio_io_error(bio); - return; - } - if (unlikely(bio_end_sector(bio) > tmp_dev->end_sector)) { - /* This bio crosses a device boundary, so we have to - * split it. - */ - struct bio_pair *bp; - sector_t end_sector = tmp_dev->end_sector; + do { + rcu_read_lock(); - rcu_read_unlock(); - - bp = bio_pair_split(bio, end_sector - bio->bi_iter.bi_sector); + tmp_dev = which_dev(mddev, bio->bi_iter.bi_sector); + start_sector = tmp_dev->end_sector - tmp_dev->rdev->sectors; + end_sector = tmp_dev->end_sector; + data_offset = tmp_dev->rdev->data_offset; + bio->bi_bdev = tmp_dev->rdev->bdev; - linear_make_request(mddev, &bp->bio1); - linear_make_request(mddev, &bp->bio2); - bio_pair_release(bp); - return; - } - - bio->bi_bdev = tmp_dev->rdev->bdev; - bio->bi_iter.bi_sector = bio->bi_iter.bi_sector - start_sector - + tmp_dev->rdev->data_offset; - rcu_read_unlock(); + rcu_read_unlock(); - if (unlikely((bio->bi_rw & REQ_DISCARD) && - !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) { - /* Just ignore it */ - bio_endio(bio, 0); - return; - } + if (unlikely(bio->bi_iter.bi_sector >= end_sector || + bio->bi_iter.bi_sector < start_sector)) + goto out_of_bounds; + + if (unlikely(bio_end_sector(bio) > end_sector)) { + /* This bio crosses a device boundary, so we have to + * split it. + */ + split = bio_split(bio, end_sector - + bio->bi_iter.bi_sector, + GFP_NOIO, fs_bio_set); + bio_chain(split, bio); + } else { + split = bio; + } - generic_make_request(bio); + split->bi_iter.bi_sector = split->bi_iter.bi_sector - + start_sector + data_offset; + + if (unlikely((split->bi_rw & REQ_DISCARD) && + !blk_queue_discard(bdev_get_queue(split->bi_bdev)))) { + /* Just ignore it */ + bio_endio(split, 0); + } else + generic_make_request(split); + } while (split != bio); + return; + +out_of_bounds: + printk(KERN_ERR + "md/linear:%s: make_request: Sector %llu out of bounds on " + "dev %s: %llu sectors, offset %llu\n", + mdname(mddev), + (unsigned long long)bio->bi_iter.bi_sector, + bdevname(tmp_dev->rdev->bdev, b), + (unsigned long long)tmp_dev->rdev->sectors, + (unsigned long long)start_sector); + bio_io_error(bio); } static void linear_status (struct seq_file *seq, struct mddev *mddev) diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index ea754dd1a5f5..407a99e46f69 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -513,65 +513,44 @@ static inline int is_io_in_chunk_boundary(struct mddev *mddev, static void raid0_make_request(struct mddev *mddev, struct bio *bio) { - unsigned int chunk_sects; - sector_t sector_offset; struct strip_zone *zone; struct md_rdev *tmp_dev; + struct bio *split; if (unlikely(bio->bi_rw & REQ_FLUSH)) { md_flush_request(mddev, bio); return; } - chunk_sects = mddev->chunk_sectors; - if (unlikely(!is_io_in_chunk_boundary(mddev, chunk_sects, bio))) { + do { sector_t sector = bio->bi_iter.bi_sector; - struct bio_pair *bp; - /* Sanity check -- queue functions should prevent this happening */ - if (bio_multiple_segments(bio)) - goto bad_map; - /* This is a one page bio that upper layers - * refuse to split for us, so we need to split it. - */ - if (likely(is_power_of_2(chunk_sects))) - bp = bio_pair_split(bio, chunk_sects - (sector & - (chunk_sects-1))); - else - bp = bio_pair_split(bio, chunk_sects - - sector_div(sector, chunk_sects)); - raid0_make_request(mddev, &bp->bio1); - raid0_make_request(mddev, &bp->bio2); - bio_pair_release(bp); - return; - } - - sector_offset = bio->bi_iter.bi_sector; - zone = find_zone(mddev->private, §or_offset); - tmp_dev = map_sector(mddev, zone, bio->bi_iter.bi_sector, - §or_offset); - bio->bi_bdev = tmp_dev->bdev; - bio->bi_iter.bi_sector = sector_offset + zone->dev_start + - tmp_dev->data_offset; - - if (unlikely((bio->bi_rw & REQ_DISCARD) && - !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) { - /* Just ignore it */ - bio_endio(bio, 0); - return; - } - - generic_make_request(bio); - return; - -bad_map: - printk("md/raid0:%s: make_request bug: can't convert block across chunks" - " or bigger than %dk %llu %d\n", - mdname(mddev), chunk_sects / 2, - (unsigned long long)bio->bi_iter.bi_sector, - bio_sectors(bio) / 2); + unsigned chunk_sects = mddev->chunk_sectors; + + unsigned sectors = chunk_sects - + (likely(is_power_of_2(chunk_sects)) + ? (sector & (chunk_sects-1)) + : sector_div(sector, chunk_sects)); + + if (sectors < bio_sectors(bio)) { + split = bio_split(bio, sectors, GFP_NOIO, fs_bio_set); + bio_chain(split, bio); + } else { + split = bio; + } - bio_io_error(bio); - return; + zone = find_zone(mddev->private, §or); + tmp_dev = map_sector(mddev, zone, sector, §or); + split->bi_bdev = tmp_dev->bdev; + split->bi_iter.bi_sector = sector + zone->dev_start + + tmp_dev->data_offset; + + if (unlikely((split->bi_rw & REQ_DISCARD) && + !blk_queue_discard(bdev_get_queue(split->bi_bdev)))) { + /* Just ignore it */ + bio_endio(split, 0); + } else + generic_make_request(split); + } while (split != bio); } static void raid0_status(struct seq_file *seq, struct mddev *mddev) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 69c1bc8da88f..6d43d88657aa 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1152,14 +1152,12 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule) kfree(plug); } -static void make_request(struct mddev *mddev, struct bio * bio) +static void __make_request(struct mddev *mddev, struct bio *bio) { struct r10conf *conf = mddev->private; struct r10bio *r10_bio; struct bio *read_bio; int i; - sector_t chunk_mask = (conf->geo.chunk_mask & conf->prev.chunk_mask); - int chunk_sects = chunk_mask + 1; const int rw = bio_data_dir(bio); const unsigned long do_sync = (bio->bi_rw & REQ_SYNC); const unsigned long do_fua = (bio->bi_rw & REQ_FUA); @@ -1174,69 +1172,6 @@ static void make_request(struct mddev *mddev, struct bio * bio) int max_sectors; int sectors; - if (unlikely(bio->bi_rw & REQ_FLUSH)) { - md_flush_request(mddev, bio); - return; - } - - /* If this request crosses a chunk boundary, we need to - * split it. This will only happen for 1 PAGE (or less) requests. - */ - if (unlikely((bio->bi_iter.bi_sector & chunk_mask) + bio_sectors(bio) - > chunk_sects - && (conf->geo.near_copies < conf->geo.raid_disks - || conf->prev.near_copies < conf->prev.raid_disks))) { - struct bio_pair *bp; - /* Sanity check -- queue functions should prevent this happening */ - if (bio_multiple_segments(bio)) - goto bad_map; - /* This is a one page bio that upper layers - * refuse to split for us, so we need to split it. - */ - bp = bio_pair_split(bio, chunk_sects - - (bio->bi_iter.bi_sector & (chunk_sects - 1))); - - /* Each of these 'make_request' calls will call 'wait_barrier'. - * If the first succeeds but the second blocks due to the resync - * thread raising the barrier, we will deadlock because the - * IO to the underlying device will be queued in generic_make_request - * and will never complete, so will never reduce nr_pending. - * So increment nr_waiting here so no new raise_barriers will - * succeed, and so the second wait_barrier cannot block. - */ - spin_lock_irq(&conf->resync_lock); - conf->nr_waiting++; - spin_unlock_irq(&conf->resync_lock); - - make_request(mddev, &bp->bio1); - make_request(mddev, &bp->bio2); - - spin_lock_irq(&conf->resync_lock); - conf->nr_waiting--; - wake_up(&conf->wait_barrier); - spin_unlock_irq(&conf->resync_lock); - - bio_pair_release(bp); - return; - bad_map: - printk("md/raid10:%s: make_request bug: can't convert block across chunks" - " or bigger than %dk %llu %d\n", mdname(mddev), chunk_sects/2, - (unsigned long long)bio->bi_iter.bi_sector, - bio_sectors(bio) / 2); - - bio_io_error(bio); - return; - } - - md_write_start(mddev, bio); - - /* - * Register the new request and wait if the reconstruction - * thread has put up a bar for new requests. - * Continue immediately if no resync is active currently. - */ - wait_barrier(conf); - sectors = bio_sectors(bio); while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && bio->bi_iter.bi_sector < conf->reshape_progress && @@ -1600,6 +1535,52 @@ retry_write: goto retry_write; } one_write_done(r10_bio); +} + +static void make_request(struct mddev *mddev, struct bio *bio) +{ + struct r10conf *conf = mddev->private; + sector_t chunk_mask = (conf->geo.chunk_mask & conf->prev.chunk_mask); + int chunk_sects = chunk_mask + 1; + + struct bio *split; + + if (unlikely(bio->bi_rw & REQ_FLUSH)) { + md_flush_request(mddev, bio); + return; + } + + md_write_start(mddev, bio); + + /* + * Register the new request and wait if the reconstruction + * thread has put up a bar for new requests. + * Continue immediately if no resync is active currently. + */ + wait_barrier(conf); + + do { + + /* + * If this request crosses a chunk boundary, we need to split + * it. + */ + if (unlikely((bio->bi_iter.bi_sector & chunk_mask) + + bio_sectors(bio) > chunk_sects + && (conf->geo.near_copies < conf->geo.raid_disks + || conf->prev.near_copies < + conf->prev.raid_disks))) { + split = bio_split(bio, chunk_sects - + (bio->bi_iter.bi_sector & + (chunk_sects - 1)), + GFP_NOIO, fs_bio_set); + bio_chain(split, bio); + } else { + split = bio; + } + + __make_request(mddev, split); + } while (split != bio); /* In case raid10d snuck in to freeze_array */ wake_up(&conf->wait_barrier); diff --git a/fs/bio.c b/fs/bio.c index a3e753f4d5a6..7b062befac82 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -1793,6 +1793,42 @@ void bio_endio_nodec(struct bio *bio, int error) } EXPORT_SYMBOL(bio_endio_nodec); +/** + * bio_split - split a bio + * @bio: bio to split + * @sectors: number of sectors to split from the front of @bio + * @gfp: gfp mask + * @bs: bio set to allocate from + * + * Allocates and returns a new bio which represents @sectors from the start of + * @bio, and updates @bio to represent the remaining sectors. + * + * The newly allocated bio will point to @bio's bi_io_vec; it is the caller's + * responsibility to ensure that @bio is not freed before the split. + */ +struct bio *bio_split(struct bio *bio, int sectors, + gfp_t gfp, struct bio_set *bs) +{ + struct bio *split = NULL; + + BUG_ON(sectors <= 0); + BUG_ON(sectors >= bio_sectors(bio)); + + split = bio_clone_fast(bio, gfp, bs); + if (!split) + return NULL; + + split->bi_iter.bi_size = sectors << 9; + + if (bio_integrity(split)) + bio_integrity_trim(split, 0, sectors); + + bio_advance(bio, split->bi_iter.bi_size); + + return split; +} +EXPORT_SYMBOL(bio_split); + void bio_pair_release(struct bio_pair *bp) { if (atomic_dec_and_test(&bp->cnt)) { diff --git a/include/linux/bio.h b/include/linux/bio.h index aa67af0b31ac..19e31b2f5b2c 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -321,6 +321,28 @@ extern struct bio_pair *bio_pair_split(struct bio *bi, int first_sectors); extern void bio_pair_release(struct bio_pair *dbio); extern void bio_trim(struct bio *bio, int offset, int size); +extern struct bio *bio_split(struct bio *bio, int sectors, + gfp_t gfp, struct bio_set *bs); + +/** + * bio_next_split - get next @sectors from a bio, splitting if necessary + * @bio: bio to split + * @sectors: number of sectors to split from the front of @bio + * @gfp: gfp mask + * @bs: bio set to allocate from + * + * Returns a bio representing the next @sectors of @bio - if the bio is smaller + * than @sectors, returns the original bio unchanged. + */ +static inline struct bio *bio_next_split(struct bio *bio, int sectors, + gfp_t gfp, struct bio_set *bs) +{ + if (sectors >= bio_sectors(bio)) + return bio; + + return bio_split(bio, sectors, gfp, bs); +} + extern struct bio_set *bioset_create(unsigned int, unsigned int); extern void bioset_free(struct bio_set *); extern mempool_t *biovec_create_pool(struct bio_set *bs, int pool_entries); -- cgit v1.2.3-59-g8ed1b From 4b1faf931650d4a35b2a570318862821d6a962e3 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Wed, 7 Aug 2013 14:33:00 -0700 Subject: block: Kill bio_pair_split() Signed-off-by: Kent Overstreet Cc: Jens Axboe --- fs/bio-integrity.c | 45 --------------------------- fs/bio.c | 90 ----------------------------------------------------- include/linux/bio.h | 30 ------------------ 3 files changed, 165 deletions(-) (limited to 'include/linux') diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c index 9d547d2e357c..80d972d739e5 100644 --- a/fs/bio-integrity.c +++ b/fs/bio-integrity.c @@ -580,51 +580,6 @@ void bio_integrity_trim(struct bio *bio, unsigned int offset, } EXPORT_SYMBOL(bio_integrity_trim); -/** - * bio_integrity_split - Split integrity metadata - * @bio: Protected bio - * @bp: Resulting bio_pair - * @sectors: Offset - * - * Description: Splits an integrity page into a bio_pair. - */ -void bio_integrity_split(struct bio *bio, struct bio_pair *bp, int sectors) -{ - struct blk_integrity *bi; - struct bio_integrity_payload *bip = bio->bi_integrity; - unsigned int nr_sectors; - - if (bio_integrity(bio) == 0) - return; - - bi = bdev_get_integrity(bio->bi_bdev); - BUG_ON(bi == NULL); - BUG_ON(bip->bip_vcnt != 1); - - nr_sectors = bio_integrity_hw_sectors(bi, sectors); - - bp->bio1.bi_integrity = &bp->bip1; - bp->bio2.bi_integrity = &bp->bip2; - - bp->iv1 = bip->bip_vec[bip->bip_iter.bi_idx]; - bp->iv2 = bip->bip_vec[bip->bip_iter.bi_idx]; - - bp->bip1.bip_vec = &bp->iv1; - bp->bip2.bip_vec = &bp->iv2; - - bp->iv1.bv_len = sectors * bi->tuple_size; - bp->iv2.bv_offset += sectors * bi->tuple_size; - bp->iv2.bv_len -= sectors * bi->tuple_size; - - bp->bip1.bip_iter.bi_sector = bio->bi_integrity->bip_iter.bi_sector; - bp->bip2.bip_iter.bi_sector = - bio->bi_integrity->bip_iter.bi_sector + nr_sectors; - - bp->bip1.bip_vcnt = bp->bip2.bip_vcnt = 1; - bp->bip1.bip_iter.bi_idx = bp->bip2.bip_iter.bi_idx = 0; -} -EXPORT_SYMBOL(bio_integrity_split); - /** * bio_integrity_clone - Callback for cloning bios with integrity metadata * @bio: New bio diff --git a/fs/bio.c b/fs/bio.c index 7b062befac82..75c49a382239 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -38,8 +38,6 @@ */ #define BIO_INLINE_VECS 4 -static mempool_t *bio_split_pool __read_mostly; - /* * if you change this list, also change bvec_alloc or things will * break badly! cannot be bigger than what you can fit into an @@ -1829,89 +1827,6 @@ struct bio *bio_split(struct bio *bio, int sectors, } EXPORT_SYMBOL(bio_split); -void bio_pair_release(struct bio_pair *bp) -{ - if (atomic_dec_and_test(&bp->cnt)) { - struct bio *master = bp->bio1.bi_private; - - bio_endio(master, bp->error); - mempool_free(bp, bp->bio2.bi_private); - } -} -EXPORT_SYMBOL(bio_pair_release); - -static void bio_pair_end_1(struct bio *bi, int err) -{ - struct bio_pair *bp = container_of(bi, struct bio_pair, bio1); - - if (err) - bp->error = err; - - bio_pair_release(bp); -} - -static void bio_pair_end_2(struct bio *bi, int err) -{ - struct bio_pair *bp = container_of(bi, struct bio_pair, bio2); - - if (err) - bp->error = err; - - bio_pair_release(bp); -} - -/* - * split a bio - only worry about a bio with a single page in its iovec - */ -struct bio_pair *bio_pair_split(struct bio *bi, int first_sectors) -{ - struct bio_pair *bp = mempool_alloc(bio_split_pool, GFP_NOIO); - - if (!bp) - return bp; - - trace_block_split(bdev_get_queue(bi->bi_bdev), bi, - bi->bi_iter.bi_sector + first_sectors); - - BUG_ON(bio_multiple_segments(bi)); - atomic_set(&bp->cnt, 3); - bp->error = 0; - bp->bio1 = *bi; - bp->bio2 = *bi; - bp->bio2.bi_iter.bi_sector += first_sectors; - bp->bio2.bi_iter.bi_size -= first_sectors << 9; - bp->bio1.bi_iter.bi_size = first_sectors << 9; - - if (bi->bi_vcnt != 0) { - bp->bv1 = bio_iovec(bi); - bp->bv2 = bio_iovec(bi); - - if (bio_is_rw(bi)) { - bp->bv2.bv_offset += first_sectors << 9; - bp->bv2.bv_len -= first_sectors << 9; - bp->bv1.bv_len = first_sectors << 9; - } - - bp->bio1.bi_io_vec = &bp->bv1; - bp->bio2.bi_io_vec = &bp->bv2; - - bp->bio1.bi_max_vecs = 1; - bp->bio2.bi_max_vecs = 1; - } - - bp->bio1.bi_end_io = bio_pair_end_1; - bp->bio2.bi_end_io = bio_pair_end_2; - - bp->bio1.bi_private = bi; - bp->bio2.bi_private = bio_split_pool; - - if (bio_integrity(bi)) - bio_integrity_split(bi, bp, first_sectors); - - return bp; -} -EXPORT_SYMBOL(bio_pair_split); - /** * bio_trim - trim a bio * @bio: bio to trim @@ -2113,11 +2028,6 @@ static int __init init_bio(void) if (bioset_integrity_create(fs_bio_set, BIO_POOL_SIZE)) panic("bio: can't create integrity pool\n"); - bio_split_pool = mempool_create_kmalloc_pool(BIO_SPLIT_ENTRIES, - sizeof(struct bio_pair)); - if (!bio_split_pool) - panic("bio: can't create split pool\n"); - return 0; } subsys_initcall(init_bio); diff --git a/include/linux/bio.h b/include/linux/bio.h index 19e31b2f5b2c..70654521dab6 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -297,30 +297,7 @@ struct bio_integrity_payload { }; #endif /* CONFIG_BLK_DEV_INTEGRITY */ -/* - * A bio_pair is used when we need to split a bio. - * This can only happen for a bio that refers to just one - * page of data, and in the unusual situation when the - * page crosses a chunk/device boundary - * - * The address of the master bio is stored in bio1.bi_private - * The address of the pool the pair was allocated from is stored - * in bio2.bi_private - */ -struct bio_pair { - struct bio bio1, bio2; - struct bio_vec bv1, bv2; -#if defined(CONFIG_BLK_DEV_INTEGRITY) - struct bio_integrity_payload bip1, bip2; - struct bio_vec iv1, iv2; -#endif - atomic_t cnt; - int error; -}; -extern struct bio_pair *bio_pair_split(struct bio *bi, int first_sectors); -extern void bio_pair_release(struct bio_pair *dbio); extern void bio_trim(struct bio *bio, int offset, int size); - extern struct bio *bio_split(struct bio *bio, int sectors, gfp_t gfp, struct bio_set *bs); @@ -677,7 +654,6 @@ extern int bio_integrity_prep(struct bio *); extern void bio_integrity_endio(struct bio *, int); extern void bio_integrity_advance(struct bio *, unsigned int); extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int); -extern void bio_integrity_split(struct bio *, struct bio_pair *, int); extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t); extern int bioset_integrity_create(struct bio_set *, int); extern void bioset_integrity_free(struct bio_set *); @@ -721,12 +697,6 @@ static inline int bio_integrity_clone(struct bio *bio, struct bio *bio_src, return 0; } -static inline void bio_integrity_split(struct bio *bio, struct bio_pair *bp, - int sectors) -{ - return; -} - static inline void bio_integrity_advance(struct bio *bio, unsigned int bytes_done) { -- cgit v1.2.3-59-g8ed1b From 8caa07c0e565a15f49f290ca4c6a3adf968ddd38 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 29 Oct 2013 11:39:00 +0000 Subject: iio: core: Implement devm_iio_device_{register,unregister} Add device managed devm_iio_device_{register,unregister}() to automatically unregister IIO drivers thus leading to simplified IIO driver code. Signed-off-by: Sachin Kamat Cc: Lars-Peter Clausen Tested-by: Lars-Peter Clausen Reviewed-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- Documentation/driver-model/devres.txt | 2 ++ drivers/iio/industrialio-core.c | 59 +++++++++++++++++++++++++++++++++++ include/linux/iio/iio.h | 3 ++ 3 files changed, 64 insertions(+) (limited to 'include/linux') diff --git a/Documentation/driver-model/devres.txt b/Documentation/driver-model/devres.txt index fcb34a5697ea..ffeab1dded0a 100644 --- a/Documentation/driver-model/devres.txt +++ b/Documentation/driver-model/devres.txt @@ -242,6 +242,8 @@ IIO devm_iio_device_free() devm_iio_trigger_alloc() devm_iio_trigger_free() + devm_iio_device_register() + devm_iio_device_unregister() IO region devm_request_region() diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 18f72e3d0ed6..1c280b50c74b 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -1161,6 +1161,65 @@ void iio_device_unregister(struct iio_dev *indio_dev) mutex_unlock(&indio_dev->info_exist_lock); } EXPORT_SYMBOL(iio_device_unregister); + +static void devm_iio_device_unreg(struct device *dev, void *res) +{ + iio_device_unregister(*(struct iio_dev **)res); +} + +/** + * devm_iio_device_register - Resource-managed iio_device_register() + * @dev: Device to allocate iio_dev for + * @indio_dev: Device structure filled by the device driver + * + * Managed iio_device_register. The IIO device registered with this + * function is automatically unregistered on driver detach. This function + * calls iio_device_register() internally. Refer to that function for more + * information. + * + * If an iio_dev registered with this function needs to be unregistered + * separately, devm_iio_device_unregister() must be used. + * + * RETURNS: + * 0 on success, negative error number on failure. + */ +int devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev) +{ + struct iio_dev **ptr; + int ret; + + ptr = devres_alloc(devm_iio_device_unreg, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + *ptr = indio_dev; + ret = iio_device_register(indio_dev); + if (!ret) + devres_add(dev, ptr); + else + devres_free(ptr); + + return ret; +} +EXPORT_SYMBOL_GPL(devm_iio_device_register); + +/** + * devm_iio_device_unregister - Resource-managed iio_device_unregister() + * @dev: Device this iio_dev belongs to + * @indio_dev: the iio_dev associated with the device + * + * Unregister iio_dev registered with devm_iio_device_register(). + */ +void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev) +{ + int rc; + + rc = devres_release(dev, devm_iio_device_unreg, + devm_iio_device_match, indio_dev); + WARN_ON(rc); +} +EXPORT_SYMBOL_GPL(devm_iio_device_unregister); + subsys_initcall(iio_init); module_exit(iio_exit); diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 256a90a1bea6..a8cabda4d108 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -510,6 +510,9 @@ int iio_device_register(struct iio_dev *indio_dev); **/ void iio_device_unregister(struct iio_dev *indio_dev); +int devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev); +void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev); + /** * iio_push_event() - try to add event to the list for userspace reading * @indio_dev: IIO device structure -- cgit v1.2.3-59-g8ed1b From a7e57dce02ceb8212f106191fdfbc0fcb61ce9e0 Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 29 Oct 2013 11:39:00 +0000 Subject: iio: core: Move kernel doc to the right location Documentation related to function should be placed above its implementation. Move it accordingly. Signed-off-by: Sachin Kamat Cc: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-core.c | 42 ++++++++++++++++++++ drivers/iio/industrialio-event.c | 6 +++ drivers/iio/industrialio-trigger.c | 24 ++++++++++++ include/linux/iio/iio.h | 80 -------------------------------------- 4 files changed, 72 insertions(+), 80 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 1c280b50c74b..2fe88c189f74 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -107,6 +107,11 @@ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_INT_TIME] = "integration_time", }; +/** + * iio_find_channel_from_si() - get channel from its scan index + * @indio_dev: device + * @si: scan index to match + */ const struct iio_chan_spec *iio_find_channel_from_si(struct iio_dev *indio_dev, int si) { @@ -922,6 +927,10 @@ struct device_type iio_device_type = { .release = iio_dev_release, }; +/** + * iio_device_alloc() - allocate an iio_dev from a driver + * @sizeof_priv: Space to allocate for private structure. + **/ struct iio_dev *iio_device_alloc(int sizeof_priv) { struct iio_dev *dev; @@ -962,6 +971,10 @@ struct iio_dev *iio_device_alloc(int sizeof_priv) } EXPORT_SYMBOL(iio_device_alloc); +/** + * iio_device_free() - free an iio_dev from a driver + * @dev: the iio_dev associated with the device + **/ void iio_device_free(struct iio_dev *dev) { if (dev) @@ -984,6 +997,20 @@ static int devm_iio_device_match(struct device *dev, void *res, void *data) return *r == data; } +/** + * devm_iio_device_alloc - Resource-managed iio_device_alloc() + * @dev: Device to allocate iio_dev for + * @sizeof_priv: Space to allocate for private structure. + * + * Managed iio_device_alloc. iio_dev allocated with this function is + * automatically freed on driver detach. + * + * If an iio_dev allocated with this function needs to be freed separately, + * devm_iio_device_free() must be used. + * + * RETURNS: + * Pointer to allocated iio_dev on success, NULL on failure. + */ struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv) { struct iio_dev **ptr, *iio_dev; @@ -1006,6 +1033,13 @@ struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv) } EXPORT_SYMBOL_GPL(devm_iio_device_alloc); +/** + * devm_iio_device_free - Resource-managed iio_device_free() + * @dev: Device this iio_dev belongs to + * @iio_dev: the iio_dev associated with the device + * + * Free iio_dev allocated with devm_iio_device_alloc(). + */ void devm_iio_device_free(struct device *dev, struct iio_dev *iio_dev) { int rc; @@ -1080,6 +1114,10 @@ static const struct file_operations iio_buffer_fileops = { static const struct iio_buffer_setup_ops noop_ring_setup_ops; +/** + * iio_device_register() - register a device with the IIO subsystem + * @indio_dev: Device structure filled by the device driver + **/ int iio_device_register(struct iio_dev *indio_dev) { int ret; @@ -1141,6 +1179,10 @@ error_ret: } EXPORT_SYMBOL(iio_device_register); +/** + * iio_device_unregister() - unregister a device from the IIO subsystem + * @indio_dev: Device structure representing the device. + **/ void iio_device_unregister(struct iio_dev *indio_dev) { mutex_lock(&indio_dev->info_exist_lock); diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index dac15b9f9df8..32b2c2d8d237 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -42,6 +42,12 @@ struct iio_event_interface { struct attribute_group group; }; +/** + * iio_push_event() - try to add event to the list for userspace reading + * @indio_dev: IIO device structure + * @ev_code: What event + * @timestamp: When the event occurred + **/ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp) { struct iio_event_interface *ev_int = indio_dev->event_interface; diff --git a/drivers/iio/industrialio-trigger.c b/drivers/iio/industrialio-trigger.c index bf5e70a32d3f..8bd092b9327e 100644 --- a/drivers/iio/industrialio-trigger.c +++ b/drivers/iio/industrialio-trigger.c @@ -506,6 +506,23 @@ static int devm_iio_trigger_match(struct device *dev, void *res, void *data) return *r == data; } +/** + * devm_iio_trigger_alloc - Resource-managed iio_trigger_alloc() + * @dev: Device to allocate iio_trigger for + * @fmt: trigger name format. If it includes format + * specifiers, the additional arguments following + * format are formatted and inserted in the resulting + * string replacing their respective specifiers. + * + * Managed iio_trigger_alloc. iio_trigger allocated with this function is + * automatically freed on driver detach. + * + * If an iio_trigger allocated with this function needs to be freed separately, + * devm_iio_trigger_free() must be used. + * + * RETURNS: + * Pointer to allocated iio_trigger on success, NULL on failure. + */ struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, const char *fmt, ...) { @@ -532,6 +549,13 @@ struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, } EXPORT_SYMBOL_GPL(devm_iio_trigger_alloc); +/** + * devm_iio_trigger_free - Resource-managed iio_trigger_free() + * @dev: Device this iio_dev belongs to + * @iio_trig: the iio_trigger associated with the device + * + * Free iio_trigger allocated with devm_iio_trigger_alloc(). + */ void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig) { int rc; diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index a8cabda4d108..5b125fd554e4 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -490,35 +490,12 @@ struct iio_dev { #endif }; -/** - * iio_find_channel_from_si() - get channel from its scan index - * @indio_dev: device - * @si: scan index to match - */ const struct iio_chan_spec *iio_find_channel_from_si(struct iio_dev *indio_dev, int si); - -/** - * iio_device_register() - register a device with the IIO subsystem - * @indio_dev: Device structure filled by the device driver - **/ int iio_device_register(struct iio_dev *indio_dev); - -/** - * iio_device_unregister() - unregister a device from the IIO subsystem - * @indio_dev: Device structure representing the device. - **/ void iio_device_unregister(struct iio_dev *indio_dev); - int devm_iio_device_register(struct device *dev, struct iio_dev *indio_dev); void devm_iio_device_unregister(struct device *dev, struct iio_dev *indio_dev); - -/** - * iio_push_event() - try to add event to the list for userspace reading - * @indio_dev: IIO device structure - * @ev_code: What event - * @timestamp: When the event occurred - **/ int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp); extern struct bus_type iio_bus_type; @@ -582,10 +559,6 @@ static inline void *iio_device_get_drvdata(struct iio_dev *indio_dev) /* Can we make this smaller? */ #define IIO_ALIGN L1_CACHE_BYTES -/** - * iio_device_alloc() - allocate an iio_dev from a driver - * @sizeof_priv: Space to allocate for private structure. - **/ struct iio_dev *iio_device_alloc(int sizeof_priv); static inline void *iio_priv(const struct iio_dev *indio_dev) @@ -599,64 +572,11 @@ static inline struct iio_dev *iio_priv_to_dev(void *priv) ALIGN(sizeof(struct iio_dev), IIO_ALIGN)); } -/** - * iio_device_free() - free an iio_dev from a driver - * @indio_dev: the iio_dev associated with the device - **/ void iio_device_free(struct iio_dev *indio_dev); - -/** - * devm_iio_device_alloc - Resource-managed iio_device_alloc() - * @dev: Device to allocate iio_dev for - * @sizeof_priv: Space to allocate for private structure. - * - * Managed iio_device_alloc. iio_dev allocated with this function is - * automatically freed on driver detach. - * - * If an iio_dev allocated with this function needs to be freed separately, - * devm_iio_device_free() must be used. - * - * RETURNS: - * Pointer to allocated iio_dev on success, NULL on failure. - */ struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv); - -/** - * devm_iio_device_free - Resource-managed iio_device_free() - * @dev: Device this iio_dev belongs to - * @indio_dev: the iio_dev associated with the device - * - * Free iio_dev allocated with devm_iio_device_alloc(). - */ void devm_iio_device_free(struct device *dev, struct iio_dev *indio_dev); - -/** - * devm_iio_trigger_alloc - Resource-managed iio_trigger_alloc() - * @dev: Device to allocate iio_trigger for - * @fmt: trigger name format. If it includes format - * specifiers, the additional arguments following - * format are formatted and inserted in the resulting - * string replacing their respective specifiers. - * - * Managed iio_trigger_alloc. iio_trigger allocated with this function is - * automatically freed on driver detach. - * - * If an iio_trigger allocated with this function needs to be freed separately, - * devm_iio_trigger_free() must be used. - * - * RETURNS: - * Pointer to allocated iio_trigger on success, NULL on failure. - */ struct iio_trigger *devm_iio_trigger_alloc(struct device *dev, const char *fmt, ...); - -/** - * devm_iio_trigger_free - Resource-managed iio_trigger_free() - * @dev: Device this iio_dev belongs to - * @iio_trig: the iio_trigger associated with the device - * - * Free iio_trigger allocated with devm_iio_trigger_alloc(). - */ void devm_iio_trigger_free(struct device *dev, struct iio_trigger *iio_trig); /** -- cgit v1.2.3-59-g8ed1b From 2ebac4f8ba4868cea7e18eebb13a759d38b5596f Mon Sep 17 00:00:00 2001 From: "Vishwanathrao Badarkhe, Manish" Date: Tue, 19 Nov 2013 18:02:42 +0530 Subject: gpio: Remove duplicate include of errno.h Currently, code include errno.h twice. Remove one inclusion of errno.h Signed-off-by: Vishwanathrao Badarkhe, Manish Signed-off-by: Linus Walleij --- include/linux/gpio.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/gpio.h b/include/linux/gpio.h index 13dfd24d01ab..b581b13d29d9 100644 --- a/include/linux/gpio.h +++ b/include/linux/gpio.h @@ -90,7 +90,6 @@ void devm_gpio_free(struct device *dev, unsigned int gpio); #include #include -#include #include #include -- cgit v1.2.3-59-g8ed1b From fbdd90ea830162960fb8fbe377dfef9a54d74d2f Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Mon, 11 Nov 2013 20:14:00 +0200 Subject: mac80211: enable easier manipulation of VHT beamforming caps Introduce shift and mask defines for beamformee STS cap and number of sounding dimensions cap as these can take any 3 bit value. While at it also cleanup an unrequired parenthesis. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- include/linux/ieee80211.h | 8 ++++++-- net/mac80211/vht.c | 7 +++---- 2 files changed, 9 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 8c3b26a21574..776cbb80d098 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1411,8 +1411,12 @@ struct ieee80211_vht_operation { #define IEEE80211_VHT_CAP_RXSTBC_MASK 0x00000700 #define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800 #define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000 -#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX 0x0000e000 -#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX 0x00070000 +#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT 13 +#define IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK \ + (7 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT) +#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT 16 +#define IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK \ + (7 << IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_SHIFT) #define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000 #define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000 #define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000 diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index de0112785aae..d75f35c6e1a0 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -182,16 +182,15 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, IEEE80211_VHT_CAP_SHORT_GI_160); /* remaining ones */ - if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) { + if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE) vht_cap->cap |= cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE | - IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MAX); - } + IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK); if (own_cap.cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE) vht_cap->cap |= cap_info & (IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | - IEEE80211_VHT_CAP_BEAMFORMEE_STS_MAX); + IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK); if (own_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE) vht_cap->cap |= cap_info & -- cgit v1.2.3-59-g8ed1b From 07f9e5cf8e4154ad17b92ad288be0f04fa0cb94f Mon Sep 17 00:00:00 2001 From: Denis Carikli Date: Tue, 19 Nov 2013 11:56:04 -0800 Subject: Input: tsc2007 - add device tree support. Signed-off-by: Denis Carikli Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/tsc2007.txt | 41 +++++ arch/arm/mach-imx/mach-cpuimx35.c | 2 +- arch/arm/mach-imx/mach-cpuimx51sd.c | 2 +- arch/sh/boards/mach-ecovec24/setup.c | 2 +- drivers/input/touchscreen/tsc2007.c | 173 ++++++++++++++++----- include/linux/i2c/tsc2007.h | 6 +- 6 files changed, 180 insertions(+), 46 deletions(-) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt new file mode 100644 index 000000000000..ec365e172236 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/tsc2007.txt @@ -0,0 +1,41 @@ +* Texas Instruments tsc2007 touchscreen controller + +Required properties: +- compatible: must be "ti,tsc2007". +- reg: I2C address of the chip. +- ti,x-plate-ohms: X-plate resistance in ohms. + +Optional properties: +- gpios: the interrupt gpio the chip is connected to (trough the penirq pin). + The penirq pin goes to low when the panel is touched. + (see GPIO binding[1] for more details). +- interrupt-parent: the phandle for the gpio controller + (see interrupt binding[0]). +- interrupts: (gpio) interrupt to which the chip is connected + (see interrupt binding[0]). +- ti,max-rt: maximum pressure. +- ti,fuzzx: specifies the absolute input fuzz x value. + If set, it will permit noise in the data up to +- the value given to the fuzz + parameter, that is used to filter noise from the event stream. +- ti,fuzzy: specifies the absolute input fuzz y value. +- ti,fuzzz: specifies the absolute input fuzz z value. +- ti,poll-period: how much time to wait (in milliseconds) before reading again the + values from the tsc2007. + +[0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt +[1]: Documentation/devicetree/bindings/gpio/gpio.txt + +Example: + &i2c1 { + /* ... */ + tsc2007@49 { + compatible = "ti,tsc2007"; + reg = <0x49>; + interrupt-parent = <&gpio4>; + interrupts = <0x0 0x8>; + gpios = <&gpio4 0 0>; + ti,x-plate-ohms = <180>; + }; + + /* ... */ + }; diff --git a/arch/arm/mach-imx/mach-cpuimx35.c b/arch/arm/mach-imx/mach-cpuimx35.c index 771362d1fbee..65e4c53e1554 100644 --- a/arch/arm/mach-imx/mach-cpuimx35.c +++ b/arch/arm/mach-imx/mach-cpuimx35.c @@ -53,7 +53,7 @@ static const struct imxi2c_platform_data }; #define TSC2007_IRQGPIO IMX_GPIO_NR(3, 2) -static int tsc2007_get_pendown_state(void) +static int tsc2007_get_pendown_state(struct device *dev) { return !gpio_get_value(TSC2007_IRQGPIO); } diff --git a/arch/arm/mach-imx/mach-cpuimx51sd.c b/arch/arm/mach-imx/mach-cpuimx51sd.c index 9b5ddf5bbd33..1fba2b8e983f 100644 --- a/arch/arm/mach-imx/mach-cpuimx51sd.c +++ b/arch/arm/mach-imx/mach-cpuimx51sd.c @@ -121,7 +121,7 @@ static const struct imxuart_platform_data uart_pdata __initconst = { .flags = IMXUART_HAVE_RTSCTS, }; -static int tsc2007_get_pendown_state(void) +static int tsc2007_get_pendown_state(struct device *dev) { if (mx51_revision() < IMX_CHIP_REVISION_3_0) return !gpio_get_value(TSC2007_IRQGPIO_REV2); diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 1fa8be409771..23d7e45f9d14 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -501,7 +501,7 @@ static struct platform_device keysc_device = { /* TouchScreen */ #define IRQ0 evt2irq(0x600) -static int ts_get_pendown_state(void) +static int ts_get_pendown_state(struct device *dev) { int val = 0; gpio_free(GPIO_FN_INTC_IRQ0); diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 0b67ba476b4c..88b150a0b8ee 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #define TSC2007_MEASURE_TEMP0 (0x0 << 4) #define TSC2007_MEASURE_AUX (0x2 << 4) @@ -74,13 +77,17 @@ struct tsc2007 { u16 max_rt; unsigned long poll_delay; unsigned long poll_period; + int fuzzx; + int fuzzy; + int fuzzz; + unsigned gpio; int irq; wait_queue_head_t wait; bool stopped; - int (*get_pendown_state)(void); + int (*get_pendown_state)(struct device *); void (*clear_penirq)(void); }; @@ -161,7 +168,7 @@ static bool tsc2007_is_pen_down(struct tsc2007 *ts) if (!ts->get_pendown_state) return true; - return ts->get_pendown_state(); + return ts->get_pendown_state(&ts->client->dev); } static irqreturn_t tsc2007_soft_irq(int irq, void *handle) @@ -178,7 +185,7 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) rt = tsc2007_calculate_pressure(ts, &tc); - if (rt == 0 && !ts->get_pendown_state) { + if (!rt && !ts->get_pendown_state) { /* * If pressure reported is 0 and we don't have * callback to check pendown state, we have to @@ -228,7 +235,7 @@ static irqreturn_t tsc2007_hard_irq(int irq, void *handle) { struct tsc2007 *ts = handle; - if (!ts->get_pendown_state || likely(ts->get_pendown_state())) + if (tsc2007_is_pen_down(ts)) return IRQ_WAKE_THREAD; if (ts->clear_penirq) @@ -273,35 +280,74 @@ static void tsc2007_close(struct input_dev *input_dev) tsc2007_stop(ts); } -static int tsc2007_probe(struct i2c_client *client, - const struct i2c_device_id *id) +#ifdef CONFIG_OF +static int tsc2007_get_pendown_state_gpio(struct device *dev) { - struct tsc2007 *ts; - struct tsc2007_platform_data *pdata = client->dev.platform_data; - struct input_dev *input_dev; - int err; + struct i2c_client *client = to_i2c_client(dev); + struct tsc2007 *ts = i2c_get_clientdata(client); + + return !gpio_get_value(ts->gpio); +} + +static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) +{ + struct device_node *np = client->dev.of_node; + u32 val32; + u64 val64; - if (!pdata) { - dev_err(&client->dev, "platform data is required!\n"); + if (!np) { + dev_err(&client->dev, "missing device tree data\n"); return -EINVAL; } - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_SMBUS_READ_WORD_DATA)) - return -EIO; + if (!of_property_read_u32(np, "ti,max-rt", &val32)) + ts->max_rt = val32; + else + ts->max_rt = MAX_12BIT; - ts = kzalloc(sizeof(struct tsc2007), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!ts || !input_dev) { - err = -ENOMEM; - goto err_free_mem; + if (!of_property_read_u32(np, "ti,fuzzx", &val32)) + ts->fuzzx = val32; + + if (!of_property_read_u32(np, "ti,fuzzy", &val32)) + ts->fuzzy = val32; + + if (!of_property_read_u32(np, "ti,fuzzz", &val32)) + ts->fuzzz = val32; + + if (!of_property_read_u64(np, "ti,poll-period", &val64)) + ts->poll_period = val64; + else + ts->poll_period = 1; + + if (!of_property_read_u32(np, "ti,x-plate-ohms", &val32)) { + ts->x_plate_ohms = val32; + } else { + dev_err(&client->dev, "missing ti,x-plate-ohms devicetree property."); + return -EINVAL; } - ts->client = client; - ts->irq = client->irq; - ts->input = input_dev; - init_waitqueue_head(&ts->wait); + ts->gpio = of_get_gpio(np, 0); + if (gpio_is_valid(ts->gpio)) + ts->get_pendown_state = tsc2007_get_pendown_state_gpio; + else + dev_warn(&client->dev, + "GPIO not specified in DT (of_get_gpio returned %d)\n", + ts->gpio); + return 0; +} +#else +static int tsc2007_probe_dt(struct i2c_client *client, struct tsc2007 *ts) +{ + dev_err(&client->dev, "platform data is required!\n"); + return -EINVAL; +} +#endif + +static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts, + const struct tsc2007_platform_data *pdata, + const struct i2c_device_id *id) +{ ts->model = pdata->model; ts->x_plate_ohms = pdata->x_plate_ohms; ts->max_rt = pdata->max_rt ? : MAX_12BIT; @@ -309,13 +355,54 @@ static int tsc2007_probe(struct i2c_client *client, ts->poll_period = pdata->poll_period ? : 1; ts->get_pendown_state = pdata->get_pendown_state; ts->clear_penirq = pdata->clear_penirq; + ts->fuzzx = pdata->fuzzx; + ts->fuzzy = pdata->fuzzy; + ts->fuzzz = pdata->fuzzz; if (pdata->x_plate_ohms == 0) { dev_err(&client->dev, "x_plate_ohms is not set up in platform data"); - err = -EINVAL; - goto err_free_mem; + return -EINVAL; } + return 0; +} + +static int tsc2007_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + const struct tsc2007_platform_data *pdata = dev_get_platdata(&client->dev); + struct tsc2007 *ts; + struct input_dev *input_dev; + int err; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_WORD_DATA)) + return -EIO; + + ts = devm_kzalloc(&client->dev, sizeof(struct tsc2007), GFP_KERNEL); + if (!ts) + return -ENOMEM; + + if (pdata) + err = tsc2007_probe_pdev(client, ts, pdata, id); + else + err = tsc2007_probe_dt(client, ts); + if (err) + return err; + + input_dev = input_allocate_device(); + if (!input_dev) { + err = -ENOMEM; + goto err_free_input; + }; + + i2c_set_clientdata(client, ts); + + ts->client = client; + ts->irq = client->irq; + ts->input = input_dev; + init_waitqueue_head(&ts->wait); + snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev)); @@ -331,19 +418,19 @@ static int tsc2007_probe(struct i2c_client *client, input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); - input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, pdata->fuzzx, 0); - input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, pdata->fuzzy, 0); + input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0); + input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0); input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, - pdata->fuzzz, 0); + ts->fuzzz, 0); - if (pdata->init_platform_hw) + if (pdata && pdata->init_platform_hw) pdata->init_platform_hw(); err = request_threaded_irq(ts->irq, tsc2007_hard_irq, tsc2007_soft_irq, IRQF_ONESHOT, client->dev.driver->name, ts); if (err < 0) { dev_err(&client->dev, "irq %d busy?\n", ts->irq); - goto err_free_mem; + goto err_free_input; } tsc2007_stop(ts); @@ -352,28 +439,25 @@ static int tsc2007_probe(struct i2c_client *client, if (err) goto err_free_irq; - i2c_set_clientdata(client, ts); - return 0; err_free_irq: free_irq(ts->irq, ts); - if (pdata->exit_platform_hw) + if (pdata && pdata->exit_platform_hw) pdata->exit_platform_hw(); - err_free_mem: + err_free_input: input_free_device(input_dev); - kfree(ts); return err; } static int tsc2007_remove(struct i2c_client *client) { - struct tsc2007 *ts = i2c_get_clientdata(client); - struct tsc2007_platform_data *pdata = client->dev.platform_data; + const struct tsc2007_platform_data *pdata = dev_get_platdata(&client->dev); + struct tsc2007 *ts = i2c_get_clientdata(client); free_irq(ts->irq, ts); - if (pdata->exit_platform_hw) + if (pdata && pdata->exit_platform_hw) pdata->exit_platform_hw(); input_unregister_device(ts->input); @@ -389,10 +473,19 @@ static const struct i2c_device_id tsc2007_idtable[] = { MODULE_DEVICE_TABLE(i2c, tsc2007_idtable); +#ifdef CONFIG_OF +static const struct of_device_id tsc2007_of_match[] = { + { .compatible = "ti,tsc2007" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tsc2007_of_match); +#endif + static struct i2c_driver tsc2007_driver = { .driver = { .owner = THIS_MODULE, - .name = "tsc2007" + .name = "tsc2007", + .of_match_table = of_match_ptr(tsc2007_of_match), }, .id_table = tsc2007_idtable, .probe = tsc2007_probe, diff --git a/include/linux/i2c/tsc2007.h b/include/linux/i2c/tsc2007.h index 506a9f7af51e..041c8e823664 100644 --- a/include/linux/i2c/tsc2007.h +++ b/include/linux/i2c/tsc2007.h @@ -14,9 +14,9 @@ struct tsc2007_platform_data { int fuzzy; int fuzzz; - int (*get_pendown_state)(void); - void (*clear_penirq)(void); /* If needed, clear 2nd level - interrupt source */ + int (*get_pendown_state)(struct device *); + /* If needed, clear 2nd level interrupt source */ + void (*clear_penirq)(void); int (*init_platform_hw)(void); void (*exit_platform_hw)(void); }; -- cgit v1.2.3-59-g8ed1b From f261d46551275abc9e92b24773b15fbb82153b63 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 19 Nov 2013 12:51:26 -0800 Subject: Input: tsc2007 - remove unused poll_delay from platform data The driver does not use poll_delay parameter, so let's remove it. Tested-by: Denis Carikli Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007.c | 2 -- include/linux/i2c/tsc2007.h | 2 -- 2 files changed, 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 88b150a0b8ee..03fbdf1e8613 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -75,7 +75,6 @@ struct tsc2007 { u16 model; u16 x_plate_ohms; u16 max_rt; - unsigned long poll_delay; unsigned long poll_period; int fuzzx; int fuzzy; @@ -351,7 +350,6 @@ static int tsc2007_probe_pdev(struct i2c_client *client, struct tsc2007 *ts, ts->model = pdata->model; ts->x_plate_ohms = pdata->x_plate_ohms; ts->max_rt = pdata->max_rt ? : MAX_12BIT; - ts->poll_delay = pdata->poll_delay ? : 1; ts->poll_period = pdata->poll_period ? : 1; ts->get_pendown_state = pdata->get_pendown_state; ts->clear_penirq = pdata->clear_penirq; diff --git a/include/linux/i2c/tsc2007.h b/include/linux/i2c/tsc2007.h index 041c8e823664..4f35b6ad3889 100644 --- a/include/linux/i2c/tsc2007.h +++ b/include/linux/i2c/tsc2007.h @@ -7,8 +7,6 @@ struct tsc2007_platform_data { u16 model; /* 2007. */ u16 x_plate_ohms; /* must be non-zero value */ u16 max_rt; /* max. resistance above which samples are ignored */ - unsigned long poll_delay; /* delay (in ms) after pen-down event - before polling starts */ unsigned long poll_period; /* time (in ms) between samples */ int fuzzx; /* fuzz factor for X, Y and pressure axes */ int fuzzy; -- cgit v1.2.3-59-g8ed1b From c293738e6d8dfb9c941759855b5161fde449644d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 29 Jun 2013 10:40:20 +0200 Subject: zorro: Do not allocate zorro_autocon[] statically Currently the array of Zorro devices is allocated statically, wasting up to 4.5 KiB when running an Amiga or multi-platform kernel on a machine with no or a handful of Zorro expansion cards. Convert it to conditional dynamic memory allocation to fix this. amiga_parse_bootinfo() still needs to store some information about the detected Zorro devices, at a time even the bootmem allocator is not yet available. This is now handled using a much smaller array (typically less than 0.5 KiB), which is __initdata and thus freed later. Signed-off-by: Geert Uytterhoeven --- arch/m68k/amiga/config.c | 6 +++--- arch/m68k/amiga/platform.c | 4 ++-- drivers/zorro/zorro.c | 19 ++++++++++++++++--- include/linux/zorro.h | 18 +++++++++++++++++- 4 files changed, 38 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 93ab423758da..d956ddbfebe1 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -174,12 +174,12 @@ int __init amiga_parse_bootinfo(const struct bi_record *record) #ifdef CONFIG_ZORRO if (zorro_num_autocon < ZORRO_NUM_AUTO) { const struct ConfigDev *cd = (struct ConfigDev *)data; - struct zorro_dev *dev = &zorro_autocon[zorro_num_autocon++]; + struct zorro_dev_init *dev = &zorro_autocon_init[zorro_num_autocon++]; dev->rom = cd->cd_Rom; dev->slotaddr = cd->cd_SlotAddr; dev->slotsize = cd->cd_SlotSize; - dev->resource.start = (unsigned long)cd->cd_BoardAddr; - dev->resource.end = dev->resource.start + cd->cd_BoardSize - 1; + dev->boardaddr = (u32)cd->cd_BoardAddr; + dev->boardsize = cd->cd_BoardSize; } else printk("amiga_parse_bootinfo: too many AutoConfig devices\n"); #endif /* CONFIG_ZORRO */ diff --git a/arch/m68k/amiga/platform.c b/arch/m68k/amiga/platform.c index dacd9f911f71..7847b2b1b5b6 100644 --- a/arch/m68k/amiga/platform.c +++ b/arch/m68k/amiga/platform.c @@ -67,8 +67,8 @@ static int __init z_dev_present(zorro_id id) unsigned int i; for (i = 0; i < zorro_num_autocon; i++) - if (zorro_autocon[i].rom.er_Manufacturer == ZORRO_MANUF(id) && - zorro_autocon[i].rom.er_Product == ZORRO_PROD(id)) + if (zorro_autocon_init[i].rom.er_Manufacturer == ZORRO_MANUF(id) && + zorro_autocon_init[i].rom.er_Product == ZORRO_PROD(id)) return 1; return 0; diff --git a/drivers/zorro/zorro.c b/drivers/zorro/zorro.c index 858c9714b2f3..10c7f77aec08 100644 --- a/drivers/zorro/zorro.c +++ b/drivers/zorro/zorro.c @@ -29,7 +29,8 @@ */ unsigned int zorro_num_autocon; -struct zorro_dev zorro_autocon[ZORRO_NUM_AUTO]; +struct zorro_dev_init zorro_autocon_init[ZORRO_NUM_AUTO] __initdata; +struct zorro_dev *zorro_autocon; /* @@ -38,6 +39,7 @@ struct zorro_dev zorro_autocon[ZORRO_NUM_AUTO]; struct zorro_bus { struct device dev; + struct zorro_dev devices[0]; }; @@ -125,16 +127,20 @@ static struct resource __init *zorro_find_parent_resource( static int __init amiga_zorro_probe(struct platform_device *pdev) { struct zorro_bus *bus; + struct zorro_dev_init *zi; struct zorro_dev *z; struct resource *r; unsigned int i; int error; /* Initialize the Zorro bus */ - bus = kzalloc(sizeof(*bus), GFP_KERNEL); + bus = kzalloc(sizeof(*bus) + + zorro_num_autocon * sizeof(bus->devices[0]), + GFP_KERNEL); if (!bus) return -ENOMEM; + zorro_autocon = bus->devices; bus->dev.parent = &pdev->dev; dev_set_name(&bus->dev, "zorro"); error = device_register(&bus->dev); @@ -151,15 +157,22 @@ static int __init amiga_zorro_probe(struct platform_device *pdev) /* First identify all devices ... */ for (i = 0; i < zorro_num_autocon; i++) { + zi = &zorro_autocon_init[i]; z = &zorro_autocon[i]; + + z->rom = zi->rom; z->id = (z->rom.er_Manufacturer<<16) | (z->rom.er_Product<<8); if (z->id == ZORRO_PROD_GVP_EPC_BASE) { /* GVP quirk */ - unsigned long magic = zorro_resource_start(z)+0x8000; + unsigned long magic = zi->boardaddr + 0x8000; z->id |= *(u16 *)ZTWO_VADDR(magic) & GVP_PRODMASK; } + z->slotaddr = zi->slotaddr; + z->slotsize = zi->slotsize; sprintf(z->name, "Zorro device %08x", z->id); zorro_name_device(z); + z->resource.start = zi->boardaddr; + z->resource.end = zi->boardaddr + zi->boardsize - 1; z->resource.name = z->name; r = zorro_find_parent_resource(pdev, z); error = request_resource(r, &z->resource); diff --git a/include/linux/zorro.h b/include/linux/zorro.h index dff42025649b..661cbd2a86ee 100644 --- a/include/linux/zorro.h +++ b/include/linux/zorro.h @@ -175,7 +175,23 @@ static inline struct zorro_driver *zorro_dev_driver(const struct zorro_dev *z) extern unsigned int zorro_num_autocon; /* # of autoconfig devices found */ -extern struct zorro_dev zorro_autocon[ZORRO_NUM_AUTO]; +extern struct zorro_dev *zorro_autocon; + + + /* + * Minimal information about a Zorro device, passed from bootinfo + * Only available temporarily, i.e. until initmem has been freed! + */ + +struct zorro_dev_init { + struct ExpansionRom rom; + u16 slotaddr; + u16 slotsize; + u32 boardaddr; + u32 boardsize; +}; + +extern struct zorro_dev_init zorro_autocon_init[ZORRO_NUM_AUTO] __initdata; /* -- cgit v1.2.3-59-g8ed1b From 986ea58dfb52097999cc388880505fc7a10e4779 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 3 Oct 2013 10:45:36 +0200 Subject: zorro/UAPI: Disintegrate include/linux/zorro*.h The Zorro definitions and device IDs are used by bootstraps, hence they should be exported through UAPI. Unfortunately zorro.h was never marked for export when headers_install was introduced, so it was forgotten during the big UAPI disintegration. In addition, the removal of zorro_ids.h had been sneaked into commit 7e7a43c32a8970ea2bfc3d1af353dcb1a9237769 ("PCI: don't export device IDs to userspace") before, so it was also forgotten. Split off and export the Zorro definitions used by bootstraps. Signed-off-by: Geert Uytterhoeven --- Documentation/zorro.txt | 3 +- include/linux/zorro.h | 103 +------- include/linux/zorro_ids.h | 552 ----------------------------------------- include/uapi/linux/Kbuild | 2 + include/uapi/linux/zorro.h | 113 +++++++++ include/uapi/linux/zorro_ids.h | 552 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 671 insertions(+), 654 deletions(-) delete mode 100644 include/linux/zorro_ids.h create mode 100644 include/uapi/linux/zorro.h create mode 100644 include/uapi/linux/zorro_ids.h (limited to 'include/linux') diff --git a/Documentation/zorro.txt b/Documentation/zorro.txt index d17670400564..90a64d52bea2 100644 --- a/Documentation/zorro.txt +++ b/Documentation/zorro.txt @@ -95,8 +95,9 @@ The treatment of these regions depends on the type of Zorro space: ------------- linux/include/linux/zorro.h +linux/include/uapi/linux/zorro.h +linux/include/uapi/linux/zorro_ids.h linux/arch/m68k/include/asm/zorro.h -linux/include/linux/zorro_ids.h linux/drivers/zorro /proc/bus/zorro diff --git a/include/linux/zorro.h b/include/linux/zorro.h index 661cbd2a86ee..63fbba0740c2 100644 --- a/include/linux/zorro.h +++ b/include/linux/zorro.h @@ -11,107 +11,10 @@ #ifndef _LINUX_ZORRO_H #define _LINUX_ZORRO_H -#include - - - /* - * Each Zorro board has a 32-bit ID of the form - * - * mmmmmmmmmmmmmmmmppppppppeeeeeeee - * - * with - * - * mmmmmmmmmmmmmmmm 16-bit Manufacturer ID (assigned by CBM (sigh)) - * pppppppp 8-bit Product ID (assigned by manufacturer) - * eeeeeeee 8-bit Extended Product ID (currently only used - * for some GVP boards) - */ - - -#define ZORRO_MANUF(id) ((id) >> 16) -#define ZORRO_PROD(id) (((id) >> 8) & 0xff) -#define ZORRO_EPC(id) ((id) & 0xff) - -#define ZORRO_ID(manuf, prod, epc) \ - ((ZORRO_MANUF_##manuf << 16) | ((prod) << 8) | (epc)) - -typedef __u32 zorro_id; +#include -/* Include the ID list */ -#include - - - /* - * GVP identifies most of its products through the 'extended product code' - * (epc). The epc has to be ANDed with the GVP_PRODMASK before the - * identification. - */ - -#define GVP_PRODMASK (0xf8) -#define GVP_SCSICLKMASK (0x01) - -enum GVP_flags { - GVP_IO = 0x01, - GVP_ACCEL = 0x02, - GVP_SCSI = 0x04, - GVP_24BITDMA = 0x08, - GVP_25BITDMA = 0x10, - GVP_NOBANK = 0x20, - GVP_14MHZ = 0x40, -}; - - -struct Node { - struct Node *ln_Succ; /* Pointer to next (successor) */ - struct Node *ln_Pred; /* Pointer to previous (predecessor) */ - __u8 ln_Type; - __s8 ln_Pri; /* Priority, for sorting */ - __s8 *ln_Name; /* ID string, null terminated */ -} __attribute__ ((packed)); - -struct ExpansionRom { - /* -First 16 bytes of the expansion ROM */ - __u8 er_Type; /* Board type, size and flags */ - __u8 er_Product; /* Product number, assigned by manufacturer */ - __u8 er_Flags; /* Flags */ - __u8 er_Reserved03; /* Must be zero ($ff inverted) */ - __u16 er_Manufacturer; /* Unique ID, ASSIGNED BY COMMODORE-AMIGA! */ - __u32 er_SerialNumber; /* Available for use by manufacturer */ - __u16 er_InitDiagVec; /* Offset to optional "DiagArea" structure */ - __u8 er_Reserved0c; - __u8 er_Reserved0d; - __u8 er_Reserved0e; - __u8 er_Reserved0f; -} __attribute__ ((packed)); - -/* er_Type board type bits */ -#define ERT_TYPEMASK 0xc0 -#define ERT_ZORROII 0xc0 -#define ERT_ZORROIII 0x80 - -/* other bits defined in er_Type */ -#define ERTB_MEMLIST 5 /* Link RAM into free memory list */ -#define ERTF_MEMLIST (1<<5) - -struct ConfigDev { - struct Node cd_Node; - __u8 cd_Flags; /* (read/write) */ - __u8 cd_Pad; /* reserved */ - struct ExpansionRom cd_Rom; /* copy of board's expansion ROM */ - void *cd_BoardAddr; /* where in memory the board was placed */ - __u32 cd_BoardSize; /* size of board in bytes */ - __u16 cd_SlotAddr; /* which slot number (PRIVATE) */ - __u16 cd_SlotSize; /* number of slots (PRIVATE) */ - void *cd_Driver; /* pointer to node of driver */ - struct ConfigDev *cd_NextCD; /* linked list of drivers to config */ - __u32 cd_Unused[4]; /* for whatever the driver wants */ -} __attribute__ ((packed)); - -#define ZORRO_NUM_AUTO 16 - -#ifdef __KERNEL__ - +#include #include #include #include @@ -245,6 +148,4 @@ extern DECLARE_BITMAP(zorro_unused_z2ram, 128); #define Z2RAM_CHUNKSHIFT (16) -#endif /* __KERNEL__ */ - #endif /* _LINUX_ZORRO_H */ diff --git a/include/linux/zorro_ids.h b/include/linux/zorro_ids.h deleted file mode 100644 index 74bc53bcfdcf..000000000000 --- a/include/linux/zorro_ids.h +++ /dev/null @@ -1,552 +0,0 @@ -/* - * Zorro board IDs - * - * Please keep sorted. - */ - - -#define ZORRO_MANUF_PACIFIC_PERIPHERALS 0x00D3 -#define ZORRO_PROD_PACIFIC_PERIPHERALS_SE_2000_A500 ZORRO_ID(PACIFIC_PERIPHERALS, 0x00, 0) -#define ZORRO_PROD_PACIFIC_PERIPHERALS_SCSI ZORRO_ID(PACIFIC_PERIPHERALS, 0x0A, 0) - -#define ZORRO_MANUF_MACROSYSTEMS_USA_2 0x0100 -#define ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE ZORRO_ID(MACROSYSTEMS_USA_2, 0x13, 0) - -#define ZORRO_MANUF_KUPKE_1 0x00DD -#define ZORRO_PROD_KUPKE_GOLEM_RAM_BOX_2MB ZORRO_ID(KUPKE_1, 0x00, 0) - -#define ZORRO_MANUF_MEMPHIS 0x0100 -#define ZORRO_PROD_MEMPHIS_STORMBRINGER ZORRO_ID(MEMPHIS, 0x00, 0) - -#define ZORRO_MANUF_3_STATE 0x0200 -#define ZORRO_PROD_3_STATE_MEGAMIX_2000 ZORRO_ID(3_STATE, 0x02, 0) - -#define ZORRO_MANUF_COMMODORE_BRAUNSCHWEIG 0x0201 -#define ZORRO_PROD_CBM_A2088_A2286 ZORRO_ID(COMMODORE_BRAUNSCHWEIG, 0x01, 0) -#define ZORRO_PROD_CBM_A2286 ZORRO_ID(COMMODORE_BRAUNSCHWEIG, 0x02, 0) -#define ZORRO_PROD_CBM_A4091_1 ZORRO_ID(COMMODORE_BRAUNSCHWEIG, 0x54, 0) -#define ZORRO_PROD_CBM_A2386SX_1 ZORRO_ID(COMMODORE_BRAUNSCHWEIG, 0x67, 0) - -#define ZORRO_MANUF_COMMODORE_WEST_CHESTER_1 0x0202 -#define ZORRO_PROD_CBM_A2090A ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x01, 0) -#define ZORRO_PROD_CBM_A590_A2091_1 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x02, 0) -#define ZORRO_PROD_CBM_A590_A2091_2 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x03, 0) -#define ZORRO_PROD_CBM_A2090B ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x04, 0) -#define ZORRO_PROD_CBM_A2060 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x09, 0) -#define ZORRO_PROD_CBM_A590_A2052_A2058_A2091 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x0A, 0) -#define ZORRO_PROD_CBM_A560_RAM ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x20, 0) -#define ZORRO_PROD_CBM_A2232_PROTOTYPE ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x45, 0) -#define ZORRO_PROD_CBM_A2232 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x46, 0) -#define ZORRO_PROD_CBM_A2620 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x50, 0) -#define ZORRO_PROD_CBM_A2630 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x51, 0) -#define ZORRO_PROD_CBM_A4091_2 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x54, 0) -#define ZORRO_PROD_CBM_A2065_1 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x5A, 0) -#define ZORRO_PROD_CBM_ROMULATOR ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x60, 0) -#define ZORRO_PROD_CBM_A3000_TEST_FIXTURE ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x61, 0) -#define ZORRO_PROD_CBM_A2386SX_2 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x67, 0) -#define ZORRO_PROD_CBM_A2065_2 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x70, 0) - -#define ZORRO_MANUF_COMMODORE_WEST_CHESTER_2 0x0203 -#define ZORRO_PROD_CBM_A2090A_CM ZORRO_ID(COMMODORE_WEST_CHESTER_2, 0x03, 0) - -#define ZORRO_MANUF_PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2 0x02F4 -#define ZORRO_PROD_PPS_EXP8000 ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2, 0x02, 0) - -#define ZORRO_MANUF_KOLFF_COMPUTER_SUPPLIES 0x02FF -#define ZORRO_PROD_KCS_POWER_PC_BOARD ZORRO_ID(KOLFF_COMPUTER_SUPPLIES, 0x00, 0) - -#define ZORRO_MANUF_CARDCO_1 0x03EC -#define ZORRO_PROD_CARDCO_KRONOS_2000_1 ZORRO_ID(CARDCO_1, 0x04, 0) -#define ZORRO_PROD_CARDCO_A1000_1 ZORRO_ID(CARDCO_1, 0x0C, 0) -#define ZORRO_PROD_CARDCO_ESCORT ZORRO_ID(CARDCO_1, 0x0E, 0) -#define ZORRO_PROD_CARDCO_A2410 ZORRO_ID(CARDCO_1, 0xF5, 0) - -#define ZORRO_MANUF_A_SQUARED 0x03ED -#define ZORRO_PROD_A_SQUARED_LIVE_2000 ZORRO_ID(A_SQUARED, 0x01, 0) - -#define ZORRO_MANUF_COMSPEC_COMMUNICATIONS 0x03EE -#define ZORRO_PROD_COMSPEC_COMMUNICATIONS_AX2000 ZORRO_ID(COMSPEC_COMMUNICATIONS, 0x01, 0) - -#define ZORRO_MANUF_ANAKIN_RESEARCH 0x03F1 -#define ZORRO_PROD_ANAKIN_RESEARCH_EASYL ZORRO_ID(ANAKIN_RESEARCH, 0x01, 0) - -#define ZORRO_MANUF_MICROBOTICS 0x03F2 -#define ZORRO_PROD_MICROBOTICS_STARBOARD_II ZORRO_ID(MICROBOTICS, 0x00, 0) -#define ZORRO_PROD_MICROBOTICS_STARDRIVE ZORRO_ID(MICROBOTICS, 0x02, 0) -#define ZORRO_PROD_MICROBOTICS_8_UP_A ZORRO_ID(MICROBOTICS, 0x03, 0) -#define ZORRO_PROD_MICROBOTICS_8_UP_Z ZORRO_ID(MICROBOTICS, 0x04, 0) -#define ZORRO_PROD_MICROBOTICS_DELTA_RAM ZORRO_ID(MICROBOTICS, 0x20, 0) -#define ZORRO_PROD_MICROBOTICS_8_STAR_RAM ZORRO_ID(MICROBOTICS, 0x40, 0) -#define ZORRO_PROD_MICROBOTICS_8_STAR ZORRO_ID(MICROBOTICS, 0x41, 0) -#define ZORRO_PROD_MICROBOTICS_VXL_RAM_32 ZORRO_ID(MICROBOTICS, 0x44, 0) -#define ZORRO_PROD_MICROBOTICS_VXL_68030 ZORRO_ID(MICROBOTICS, 0x45, 0) -#define ZORRO_PROD_MICROBOTICS_DELTA ZORRO_ID(MICROBOTICS, 0x60, 0) -#define ZORRO_PROD_MICROBOTICS_MBX_1200_1200Z_RAM ZORRO_ID(MICROBOTICS, 0x81, 0) -#define ZORRO_PROD_MICROBOTICS_HARDFRAME_2000_1 ZORRO_ID(MICROBOTICS, 0x96, 0) -#define ZORRO_PROD_MICROBOTICS_HARDFRAME_2000_2 ZORRO_ID(MICROBOTICS, 0x9E, 0) -#define ZORRO_PROD_MICROBOTICS_MBX_1200_1200Z ZORRO_ID(MICROBOTICS, 0xC1, 0) - -#define ZORRO_MANUF_ACCESS_ASSOCIATES_ALEGRA 0x03F4 - -#define ZORRO_MANUF_EXPANSION_TECHNOLOGIES 0x03F6 - -#define ZORRO_MANUF_ASDG 0x03FF -#define ZORRO_PROD_ASDG_MEMORY_1 ZORRO_ID(ASDG, 0x01, 0) -#define ZORRO_PROD_ASDG_MEMORY_2 ZORRO_ID(ASDG, 0x02, 0) -#define ZORRO_PROD_ASDG_EB920_LAN_ROVER ZORRO_ID(ASDG, 0xFE, 0) -#define ZORRO_PROD_ASDG_GPIB_DUALIEEE488_TWIN_X ZORRO_ID(ASDG, 0xFF, 0) - -#define ZORRO_MANUF_IMTRONICS_1 0x0404 -#define ZORRO_PROD_IMTRONICS_HURRICANE_2800_1 ZORRO_ID(IMTRONICS_1, 0x39, 0) -#define ZORRO_PROD_IMTRONICS_HURRICANE_2800_2 ZORRO_ID(IMTRONICS_1, 0x57, 0) - -#define ZORRO_MANUF_CBM_UNIVERSITY_OF_LOWELL 0x0406 -#define ZORRO_PROD_CBM_A2410 ZORRO_ID(CBM_UNIVERSITY_OF_LOWELL, 0x00, 0) - -#define ZORRO_MANUF_AMERISTAR 0x041D -#define ZORRO_PROD_AMERISTAR_A2065 ZORRO_ID(AMERISTAR, 0x01, 0) -#define ZORRO_PROD_AMERISTAR_A560 ZORRO_ID(AMERISTAR, 0x09, 0) -#define ZORRO_PROD_AMERISTAR_A4066 ZORRO_ID(AMERISTAR, 0x0A, 0) - -#define ZORRO_MANUF_SUPRA 0x0420 -#define ZORRO_PROD_SUPRA_SUPRADRIVE_4x4 ZORRO_ID(SUPRA, 0x01, 0) -#define ZORRO_PROD_SUPRA_1000_RAM ZORRO_ID(SUPRA, 0x02, 0) -#define ZORRO_PROD_SUPRA_2000_DMA ZORRO_ID(SUPRA, 0x03, 0) -#define ZORRO_PROD_SUPRA_500 ZORRO_ID(SUPRA, 0x05, 0) -#define ZORRO_PROD_SUPRA_500_SCSI ZORRO_ID(SUPRA, 0x08, 0) -#define ZORRO_PROD_SUPRA_500XP_2000_RAM ZORRO_ID(SUPRA, 0x09, 0) -#define ZORRO_PROD_SUPRA_500RX_2000_RAM ZORRO_ID(SUPRA, 0x0A, 0) -#define ZORRO_PROD_SUPRA_2400ZI ZORRO_ID(SUPRA, 0x0B, 0) -#define ZORRO_PROD_SUPRA_500XP_SUPRADRIVE_WORDSYNC ZORRO_ID(SUPRA, 0x0C, 0) -#define ZORRO_PROD_SUPRA_SUPRADRIVE_WORDSYNC_II ZORRO_ID(SUPRA, 0x0D, 0) -#define ZORRO_PROD_SUPRA_2400ZIPLUS ZORRO_ID(SUPRA, 0x10, 0) - -#define ZORRO_MANUF_COMPUTER_SYSTEMS_ASSOCIATES 0x0422 -#define ZORRO_PROD_CSA_MAGNUM ZORRO_ID(COMPUTER_SYSTEMS_ASSOCIATES, 0x11, 0) -#define ZORRO_PROD_CSA_12_GAUGE ZORRO_ID(COMPUTER_SYSTEMS_ASSOCIATES, 0x15, 0) - -#define ZORRO_MANUF_MARC_MICHAEL_GROTH 0x0439 - -#define ZORRO_MANUF_M_TECH 0x0502 -#define ZORRO_PROD_MTEC_AT500_1 ZORRO_ID(M_TECH, 0x03, 0) - -#define ZORRO_MANUF_GREAT_VALLEY_PRODUCTS_1 0x06E1 -#define ZORRO_PROD_GVP_IMPACT_SERIES_I ZORRO_ID(GREAT_VALLEY_PRODUCTS_1, 0x08, 0) - -#define ZORRO_MANUF_BYTEBOX 0x07DA -#define ZORRO_PROD_BYTEBOX_A500 ZORRO_ID(BYTEBOX, 0x00, 0) - -#define ZORRO_MANUF_DKB_POWER_COMPUTING 0x07DC -#define ZORRO_PROD_DKB_POWER_COMPUTING_SECUREKEY ZORRO_ID(DKB_POWER_COMPUTING, 0x09, 0) -#define ZORRO_PROD_DKB_POWER_COMPUTING_DKM_3128 ZORRO_ID(DKB_POWER_COMPUTING, 0x0E, 0) -#define ZORRO_PROD_DKB_POWER_COMPUTING_RAPID_FIRE ZORRO_ID(DKB_POWER_COMPUTING, 0x0F, 0) -#define ZORRO_PROD_DKB_POWER_COMPUTING_DKM_1202 ZORRO_ID(DKB_POWER_COMPUTING, 0x10, 0) -#define ZORRO_PROD_DKB_POWER_COMPUTING_COBRA_VIPER_II_68EC030 ZORRO_ID(DKB_POWER_COMPUTING, 0x12, 0) -#define ZORRO_PROD_DKB_POWER_COMPUTING_WILDFIRE_060_1 ZORRO_ID(DKB_POWER_COMPUTING, 0x17, 0) -#define ZORRO_PROD_DKB_POWER_COMPUTING_WILDFIRE_060_2 ZORRO_ID(DKB_POWER_COMPUTING, 0xFF, 0) - -#define ZORRO_MANUF_GREAT_VALLEY_PRODUCTS_2 0x07E1 -#define ZORRO_PROD_GVP_IMPACT_SERIES_I_4K ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x01, 0) -#define ZORRO_PROD_GVP_IMPACT_SERIES_I_16K_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x02, 0) -#define ZORRO_PROD_GVP_IMPACT_SERIES_I_16K_3 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x03, 0) -#define ZORRO_PROD_GVP_IMPACT_3001_IDE_1 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x08, 0) -#define ZORRO_PROD_GVP_IMPACT_3001_RAM ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x09, 0) -#define ZORRO_PROD_GVP_IMPACT_SERIES_II_RAM_1 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0A, 0) -#define ZORRO_PROD_GVP_EPC_BASE ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0) -#define ZORRO_PROD_GVP_GFORCE_040_1 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x20) -#define ZORRO_PROD_GVP_GFORCE_040_SCSI_1 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x30) -#define ZORRO_PROD_GVP_A1291 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x40) -#define ZORRO_PROD_GVP_COMBO_030_R4 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x60) -#define ZORRO_PROD_GVP_COMBO_030_R4_SCSI ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x70) -#define ZORRO_PROD_GVP_PHONEPAK ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x78) -#define ZORRO_PROD_GVP_IO_EXTENDER ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x98) -#define ZORRO_PROD_GVP_GFORCE_030 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xa0) -#define ZORRO_PROD_GVP_GFORCE_030_SCSI ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xb0) -#define ZORRO_PROD_GVP_A530 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xc0) -#define ZORRO_PROD_GVP_A530_SCSI ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xd0) -#define ZORRO_PROD_GVP_COMBO_030_R3 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xe0) -#define ZORRO_PROD_GVP_COMBO_030_R3_SCSI ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xf0) -#define ZORRO_PROD_GVP_SERIES_II ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xf8) -#define ZORRO_PROD_GVP_IMPACT_3001_IDE_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0D, 0) -/*#define ZORRO_PROD_GVP_A2000_030 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0D, 0)*/ -/*#define ZORRO_PROD_GVP_GFORCE_040_SCSI_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0D, 0)*/ -#define ZORRO_PROD_GVP_GFORCE_040_060 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x16, 0) -#define ZORRO_PROD_GVP_IMPACT_VISION_24 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x20, 0) -#define ZORRO_PROD_GVP_GFORCE_040_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0xFF, 0) - -#define ZORRO_MANUF_CALIFORNIA_ACCESS_SYNERGY 0x07E5 -#define ZORRO_PROD_CALIFORNIA_ACCESS_SYNERGY_MALIBU ZORRO_ID(CALIFORNIA_ACCESS_SYNERGY, 0x01, 0) - -#define ZORRO_MANUF_XETEC 0x07E6 -#define ZORRO_PROD_XETEC_FASTCARD ZORRO_ID(XETEC, 0x01, 0) -#define ZORRO_PROD_XETEC_FASTCARD_RAM ZORRO_ID(XETEC, 0x02, 0) -#define ZORRO_PROD_XETEC_FASTCARD_PLUS ZORRO_ID(XETEC, 0x03, 0) - -#define ZORRO_MANUF_PROGRESSIVE_PERIPHERALS_AND_SYSTEMS 0x07EA -#define ZORRO_PROD_PPS_MERCURY ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0x00, 0) -#define ZORRO_PROD_PPS_A3000_68040 ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0x01, 0) -#define ZORRO_PROD_PPS_A2000_68040 ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0x69, 0) -#define ZORRO_PROD_PPS_ZEUS ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0x96, 0) -#define ZORRO_PROD_PPS_A500_68040 ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0xBB, 0) - -#define ZORRO_MANUF_XEBEC 0x07EC - -#define ZORRO_MANUF_SPIRIT_TECHNOLOGY 0x07F2 -#define ZORRO_PROD_SPIRIT_TECHNOLOGY_INSIDER_IN1000 ZORRO_ID(SPIRIT_TECHNOLOGY, 0x01, 0) -#define ZORRO_PROD_SPIRIT_TECHNOLOGY_INSIDER_IN500 ZORRO_ID(SPIRIT_TECHNOLOGY, 0x02, 0) -#define ZORRO_PROD_SPIRIT_TECHNOLOGY_SIN500 ZORRO_ID(SPIRIT_TECHNOLOGY, 0x03, 0) -#define ZORRO_PROD_SPIRIT_TECHNOLOGY_HDA_506 ZORRO_ID(SPIRIT_TECHNOLOGY, 0x04, 0) -#define ZORRO_PROD_SPIRIT_TECHNOLOGY_AX_S ZORRO_ID(SPIRIT_TECHNOLOGY, 0x05, 0) -#define ZORRO_PROD_SPIRIT_TECHNOLOGY_OCTABYTE ZORRO_ID(SPIRIT_TECHNOLOGY, 0x06, 0) -#define ZORRO_PROD_SPIRIT_TECHNOLOGY_INMATE ZORRO_ID(SPIRIT_TECHNOLOGY, 0x08, 0) - -#define ZORRO_MANUF_SPIRIT_TECHNOLOGY_2 0x07F3 - -#define ZORRO_MANUF_BSC_ALFADATA_1 0x07FE -#define ZORRO_PROD_BSC_ALF_3_1 ZORRO_ID(BSC_ALFADATA_1, 0x03, 0) - -#define ZORRO_MANUF_BSC_ALFADATA_2 0x0801 -#define ZORRO_PROD_BSC_ALF_2_1 ZORRO_ID(BSC_ALFADATA_2, 0x01, 0) -#define ZORRO_PROD_BSC_ALF_2_2 ZORRO_ID(BSC_ALFADATA_2, 0x02, 0) -#define ZORRO_PROD_BSC_ALF_3_2 ZORRO_ID(BSC_ALFADATA_2, 0x03, 0) - -#define ZORRO_MANUF_CARDCO_2 0x0802 -#define ZORRO_PROD_CARDCO_KRONOS_2000_2 ZORRO_ID(CARDCO_2, 0x04, 0) -#define ZORRO_PROD_CARDCO_A1000_2 ZORRO_ID(CARDCO_2, 0x0C, 0) - -#define ZORRO_MANUF_JOCHHEIM 0x0804 -#define ZORRO_PROD_JOCHHEIM_RAM ZORRO_ID(JOCHHEIM, 0x01, 0) - -#define ZORRO_MANUF_CHECKPOINT_TECHNOLOGIES 0x0807 -#define ZORRO_PROD_CHECKPOINT_TECHNOLOGIES_SERIAL_SOLUTION ZORRO_ID(CHECKPOINT_TECHNOLOGIES, 0x00, 0) - -#define ZORRO_MANUF_EDOTRONIK 0x0810 -#define ZORRO_PROD_EDOTRONIK_IEEE_488 ZORRO_ID(EDOTRONIK, 0x01, 0) -#define ZORRO_PROD_EDOTRONIK_8032 ZORRO_ID(EDOTRONIK, 0x02, 0) -#define ZORRO_PROD_EDOTRONIK_MULTISERIAL ZORRO_ID(EDOTRONIK, 0x03, 0) -#define ZORRO_PROD_EDOTRONIK_VIDEODIGITIZER ZORRO_ID(EDOTRONIK, 0x04, 0) -#define ZORRO_PROD_EDOTRONIK_PARALLEL_IO ZORRO_ID(EDOTRONIK, 0x05, 0) -#define ZORRO_PROD_EDOTRONIK_PIC_PROTOYPING ZORRO_ID(EDOTRONIK, 0x06, 0) -#define ZORRO_PROD_EDOTRONIK_ADC ZORRO_ID(EDOTRONIK, 0x07, 0) -#define ZORRO_PROD_EDOTRONIK_VME ZORRO_ID(EDOTRONIK, 0x08, 0) -#define ZORRO_PROD_EDOTRONIK_DSP96000 ZORRO_ID(EDOTRONIK, 0x09, 0) - -#define ZORRO_MANUF_NES_INC 0x0813 -#define ZORRO_PROD_NES_INC_RAM ZORRO_ID(NES_INC, 0x00, 0) - -#define ZORRO_MANUF_ICD 0x0817 -#define ZORRO_PROD_ICD_ADVANTAGE_2000_SCSI ZORRO_ID(ICD, 0x01, 0) -#define ZORRO_PROD_ICD_ADVANTAGE_IDE ZORRO_ID(ICD, 0x03, 0) -#define ZORRO_PROD_ICD_ADVANTAGE_2080_RAM ZORRO_ID(ICD, 0x04, 0) - -#define ZORRO_MANUF_KUPKE_2 0x0819 -#define ZORRO_PROD_KUPKE_OMTI ZORRO_ID(KUPKE_2, 0x01, 0) -#define ZORRO_PROD_KUPKE_SCSI_II ZORRO_ID(KUPKE_2, 0x02, 0) -#define ZORRO_PROD_KUPKE_GOLEM_BOX ZORRO_ID(KUPKE_2, 0x03, 0) -#define ZORRO_PROD_KUPKE_030_882 ZORRO_ID(KUPKE_2, 0x04, 0) -#define ZORRO_PROD_KUPKE_SCSI_AT ZORRO_ID(KUPKE_2, 0x05, 0) - -#define ZORRO_MANUF_GREAT_VALLEY_PRODUCTS_3 0x081D -#define ZORRO_PROD_GVP_A2000_RAM8 ZORRO_ID(GREAT_VALLEY_PRODUCTS_3, 0x09, 0) -#define ZORRO_PROD_GVP_IMPACT_SERIES_II_RAM_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_3, 0x0A, 0) - -#define ZORRO_MANUF_INTERWORKS_NETWORK 0x081E - -#define ZORRO_MANUF_HARDITAL_SYNTHESIS 0x0820 -#define ZORRO_PROD_HARDITAL_SYNTHESIS_TQM_68030_68882 ZORRO_ID(HARDITAL_SYNTHESIS, 0x14, 0) - -#define ZORRO_MANUF_APPLIED_ENGINEERING 0x0828 -#define ZORRO_PROD_APPLIED_ENGINEERING_DL2000 ZORRO_ID(APPLIED_ENGINEERING, 0x10, 0) -#define ZORRO_PROD_APPLIED_ENGINEERING_RAM_WORKS ZORRO_ID(APPLIED_ENGINEERING, 0xE0, 0) - -#define ZORRO_MANUF_BSC_ALFADATA_3 0x082C -#define ZORRO_PROD_BSC_OKTAGON_2008 ZORRO_ID(BSC_ALFADATA_3, 0x05, 0) -#define ZORRO_PROD_BSC_TANDEM_AT_2008_508 ZORRO_ID(BSC_ALFADATA_3, 0x06, 0) -#define ZORRO_PROD_BSC_ALFA_RAM_1200 ZORRO_ID(BSC_ALFADATA_3, 0x07, 0) -#define ZORRO_PROD_BSC_OKTAGON_2008_RAM ZORRO_ID(BSC_ALFADATA_3, 0x08, 0) -#define ZORRO_PROD_BSC_MULTIFACE_I ZORRO_ID(BSC_ALFADATA_3, 0x10, 0) -#define ZORRO_PROD_BSC_MULTIFACE_II ZORRO_ID(BSC_ALFADATA_3, 0x11, 0) -#define ZORRO_PROD_BSC_MULTIFACE_III ZORRO_ID(BSC_ALFADATA_3, 0x12, 0) -#define ZORRO_PROD_BSC_FRAMEMASTER_II ZORRO_ID(BSC_ALFADATA_3, 0x20, 0) -#define ZORRO_PROD_BSC_GRAFFITI_RAM ZORRO_ID(BSC_ALFADATA_3, 0x21, 0) -#define ZORRO_PROD_BSC_GRAFFITI_REG ZORRO_ID(BSC_ALFADATA_3, 0x22, 0) -#define ZORRO_PROD_BSC_ISDN_MASTERCARD ZORRO_ID(BSC_ALFADATA_3, 0x40, 0) -#define ZORRO_PROD_BSC_ISDN_MASTERCARD_II ZORRO_ID(BSC_ALFADATA_3, 0x41, 0) - -#define ZORRO_MANUF_PHOENIX 0x0835 -#define ZORRO_PROD_PHOENIX_ST506 ZORRO_ID(PHOENIX, 0x21, 0) -#define ZORRO_PROD_PHOENIX_SCSI ZORRO_ID(PHOENIX, 0x22, 0) -#define ZORRO_PROD_PHOENIX_RAM ZORRO_ID(PHOENIX, 0xBE, 0) - -#define ZORRO_MANUF_ADVANCED_STORAGE_SYSTEMS 0x0836 -#define ZORRO_PROD_ADVANCED_STORAGE_SYSTEMS_NEXUS ZORRO_ID(ADVANCED_STORAGE_SYSTEMS, 0x01, 0) -#define ZORRO_PROD_ADVANCED_STORAGE_SYSTEMS_NEXUS_RAM ZORRO_ID(ADVANCED_STORAGE_SYSTEMS, 0x08, 0) - -#define ZORRO_MANUF_IMPULSE 0x0838 -#define ZORRO_PROD_IMPULSE_FIRECRACKER_24 ZORRO_ID(IMPULSE, 0x00, 0) - -#define ZORRO_MANUF_IVS 0x0840 -#define ZORRO_PROD_IVS_GRANDSLAM_PIC_2 ZORRO_ID(IVS, 0x02, 0) -#define ZORRO_PROD_IVS_GRANDSLAM_PIC_1 ZORRO_ID(IVS, 0x04, 0) -#define ZORRO_PROD_IVS_OVERDRIVE ZORRO_ID(IVS, 0x10, 0) -#define ZORRO_PROD_IVS_TRUMPCARD_CLASSIC ZORRO_ID(IVS, 0x30, 0) -#define ZORRO_PROD_IVS_TRUMPCARD_PRO_GRANDSLAM ZORRO_ID(IVS, 0x34, 0) -#define ZORRO_PROD_IVS_META_4 ZORRO_ID(IVS, 0x40, 0) -#define ZORRO_PROD_IVS_WAVETOOLS ZORRO_ID(IVS, 0xBF, 0) -#define ZORRO_PROD_IVS_VECTOR_1 ZORRO_ID(IVS, 0xF3, 0) -#define ZORRO_PROD_IVS_VECTOR_2 ZORRO_ID(IVS, 0xF4, 0) - -#define ZORRO_MANUF_VECTOR_1 0x0841 -#define ZORRO_PROD_VECTOR_CONNECTION_1 ZORRO_ID(VECTOR_1, 0xE3, 0) - -#define ZORRO_MANUF_XPERT_PRODEV 0x0845 -#define ZORRO_PROD_XPERT_PRODEV_VISIONA_RAM ZORRO_ID(XPERT_PRODEV, 0x01, 0) -#define ZORRO_PROD_XPERT_PRODEV_VISIONA_REG ZORRO_ID(XPERT_PRODEV, 0x02, 0) -#define ZORRO_PROD_XPERT_PRODEV_MERLIN_RAM ZORRO_ID(XPERT_PRODEV, 0x03, 0) -#define ZORRO_PROD_XPERT_PRODEV_MERLIN_REG_1 ZORRO_ID(XPERT_PRODEV, 0x04, 0) -#define ZORRO_PROD_XPERT_PRODEV_MERLIN_REG_2 ZORRO_ID(XPERT_PRODEV, 0xC9, 0) - -#define ZORRO_MANUF_HYDRA_SYSTEMS 0x0849 -#define ZORRO_PROD_HYDRA_SYSTEMS_AMIGANET ZORRO_ID(HYDRA_SYSTEMS, 0x01, 0) - -#define ZORRO_MANUF_SUNRIZE_INDUSTRIES 0x084F -#define ZORRO_PROD_SUNRIZE_INDUSTRIES_AD1012 ZORRO_ID(SUNRIZE_INDUSTRIES, 0x01, 0) -#define ZORRO_PROD_SUNRIZE_INDUSTRIES_AD516 ZORRO_ID(SUNRIZE_INDUSTRIES, 0x02, 0) -#define ZORRO_PROD_SUNRIZE_INDUSTRIES_DD512 ZORRO_ID(SUNRIZE_INDUSTRIES, 0x03, 0) - -#define ZORRO_MANUF_TRICERATOPS 0x0850 -#define ZORRO_PROD_TRICERATOPS_MULTI_IO ZORRO_ID(TRICERATOPS, 0x01, 0) - -#define ZORRO_MANUF_APPLIED_MAGIC 0x0851 -#define ZORRO_PROD_APPLIED_MAGIC_DMI_RESOLVER ZORRO_ID(APPLIED_MAGIC, 0x01, 0) -#define ZORRO_PROD_APPLIED_MAGIC_DIGITAL_BROADCASTER ZORRO_ID(APPLIED_MAGIC, 0x06, 0) - -#define ZORRO_MANUF_GFX_BASE 0x085E -#define ZORRO_PROD_GFX_BASE_GDA_1_VRAM ZORRO_ID(GFX_BASE, 0x00, 0) -#define ZORRO_PROD_GFX_BASE_GDA_1 ZORRO_ID(GFX_BASE, 0x01, 0) - -#define ZORRO_MANUF_ROCTEC 0x0860 -#define ZORRO_PROD_ROCTEC_RH_800C ZORRO_ID(ROCTEC, 0x01, 0) -#define ZORRO_PROD_ROCTEC_RH_800C_RAM ZORRO_ID(ROCTEC, 0x01, 0) - -#define ZORRO_MANUF_KATO 0x0861 -#define ZORRO_PROD_KATO_MELODY ZORRO_ID(KATO, 0x80, 0) -/* ID clash!! */ -#define ZORRO_MANUF_HELFRICH_1 0x0861 -#define ZORRO_PROD_HELFRICH_RAINBOW_II ZORRO_ID(HELFRICH_1, 0x20, 0) -#define ZORRO_PROD_HELFRICH_RAINBOW_III ZORRO_ID(HELFRICH_1, 0x21, 0) - -#define ZORRO_MANUF_ATLANTIS 0x0862 - -#define ZORRO_MANUF_PROTAR 0x0864 - -#define ZORRO_MANUF_ACS 0x0865 - -#define ZORRO_MANUF_SOFTWARE_RESULTS_ENTERPRISES 0x0866 -#define ZORRO_PROD_SOFTWARE_RESULTS_ENTERPRISES_GOLDEN_GATE_2_BUS_PLUS ZORRO_ID(SOFTWARE_RESULTS_ENTERPRISES, 0x01, 0) - -#define ZORRO_MANUF_MASOBOSHI 0x086D -#define ZORRO_PROD_MASOBOSHI_MASTER_CARD_SC201 ZORRO_ID(MASOBOSHI, 0x03, 0) -#define ZORRO_PROD_MASOBOSHI_MASTER_CARD_MC702 ZORRO_ID(MASOBOSHI, 0x04, 0) -#define ZORRO_PROD_MASOBOSHI_MVD_819 ZORRO_ID(MASOBOSHI, 0x07, 0) - -#define ZORRO_MANUF_MAINHATTAN_DATA 0x086F -#define ZORRO_PROD_MAINHATTAN_DATA_IDE ZORRO_ID(MAINHATTAN_DATA, 0x01, 0) - -#define ZORRO_MANUF_VILLAGE_TRONIC 0x0877 -#define ZORRO_PROD_VILLAGE_TRONIC_DOMINO_RAM ZORRO_ID(VILLAGE_TRONIC, 0x01, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_DOMINO_REG ZORRO_ID(VILLAGE_TRONIC, 0x02, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_DOMINO_16M_PROTOTYPE ZORRO_ID(VILLAGE_TRONIC, 0x03, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM ZORRO_ID(VILLAGE_TRONIC, 0x0B, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG ZORRO_ID(VILLAGE_TRONIC, 0x0C, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_SEGMENTED_MODE ZORRO_ID(VILLAGE_TRONIC, 0x0D, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1 ZORRO_ID(VILLAGE_TRONIC, 0x15, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2 ZORRO_ID(VILLAGE_TRONIC, 0x16, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG ZORRO_ID(VILLAGE_TRONIC, 0x17, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3 ZORRO_ID(VILLAGE_TRONIC, 0x18, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_ARIADNE ZORRO_ID(VILLAGE_TRONIC, 0xC9, 0) -#define ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2 ZORRO_ID(VILLAGE_TRONIC, 0xCA, 0) - -#define ZORRO_MANUF_UTILITIES_UNLIMITED 0x087B -#define ZORRO_PROD_UTILITIES_UNLIMITED_EMPLANT_DELUXE ZORRO_ID(UTILITIES_UNLIMITED, 0x15, 0) -#define ZORRO_PROD_UTILITIES_UNLIMITED_EMPLANT_DELUXE2 ZORRO_ID(UTILITIES_UNLIMITED, 0x20, 0) - -#define ZORRO_MANUF_AMITRIX 0x0880 -#define ZORRO_PROD_AMITRIX_MULTI_IO ZORRO_ID(AMITRIX, 0x01, 0) -#define ZORRO_PROD_AMITRIX_CD_RAM ZORRO_ID(AMITRIX, 0x02, 0) - -#define ZORRO_MANUF_ARMAX 0x0885 -#define ZORRO_PROD_ARMAX_OMNIBUS ZORRO_ID(ARMAX, 0x00, 0) - -#define ZORRO_MANUF_ZEUS 0x088D -#define ZORRO_PROD_ZEUS_SPIDER ZORRO_ID(ZEUS, 0x04, 0) - -#define ZORRO_MANUF_NEWTEK 0x088F -#define ZORRO_PROD_NEWTEK_VIDEOTOASTER ZORRO_ID(NEWTEK, 0x00, 0) - -#define ZORRO_MANUF_M_TECH_GERMANY 0x0890 -#define ZORRO_PROD_MTEC_AT500_2 ZORRO_ID(M_TECH_GERMANY, 0x01, 0) -#define ZORRO_PROD_MTEC_68030 ZORRO_ID(M_TECH_GERMANY, 0x03, 0) -#define ZORRO_PROD_MTEC_68020I ZORRO_ID(M_TECH_GERMANY, 0x06, 0) -#define ZORRO_PROD_MTEC_A1200_T68030_RTC ZORRO_ID(M_TECH_GERMANY, 0x20, 0) -#define ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530 ZORRO_ID(M_TECH_GERMANY, 0x21, 0) -#define ZORRO_PROD_MTEC_8_MB_RAM ZORRO_ID(M_TECH_GERMANY, 0x22, 0) -#define ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE ZORRO_ID(M_TECH_GERMANY, 0x24, 0) - -#define ZORRO_MANUF_GREAT_VALLEY_PRODUCTS_4 0x0891 -#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM ZORRO_ID(GREAT_VALLEY_PRODUCTS_4, 0x01, 0) -#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG ZORRO_ID(GREAT_VALLEY_PRODUCTS_4, 0x02, 0) - -#define ZORRO_MANUF_APOLLO_1 0x0892 -#define ZORRO_PROD_APOLLO_A1200 ZORRO_ID(APOLLO_1, 0x01, 0) - -#define ZORRO_MANUF_HELFRICH_2 0x0893 -#define ZORRO_PROD_HELFRICH_PICCOLO_RAM ZORRO_ID(HELFRICH_2, 0x05, 0) -#define ZORRO_PROD_HELFRICH_PICCOLO_REG ZORRO_ID(HELFRICH_2, 0x06, 0) -#define ZORRO_PROD_HELFRICH_PEGGY_PLUS_MPEG ZORRO_ID(HELFRICH_2, 0x07, 0) -#define ZORRO_PROD_HELFRICH_VIDEOCRUNCHER ZORRO_ID(HELFRICH_2, 0x08, 0) -#define ZORRO_PROD_HELFRICH_SD64_RAM ZORRO_ID(HELFRICH_2, 0x0A, 0) -#define ZORRO_PROD_HELFRICH_SD64_REG ZORRO_ID(HELFRICH_2, 0x0B, 0) - -#define ZORRO_MANUF_MACROSYSTEMS_USA 0x089B -#define ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx ZORRO_ID(MACROSYSTEMS_USA, 0x13, 0) - -#define ZORRO_MANUF_ELBOX_COMPUTER 0x089E -#define ZORRO_PROD_ELBOX_COMPUTER_1200_4 ZORRO_ID(ELBOX_COMPUTER, 0x06, 0) - -#define ZORRO_MANUF_HARMS_PROFESSIONAL 0x0A00 -#define ZORRO_PROD_HARMS_PROFESSIONAL_030_PLUS ZORRO_ID(HARMS_PROFESSIONAL, 0x10, 0) -#define ZORRO_PROD_HARMS_PROFESSIONAL_3500 ZORRO_ID(HARMS_PROFESSIONAL, 0xD0, 0) - -#define ZORRO_MANUF_MICRONIK 0x0A50 -#define ZORRO_PROD_MICRONIK_RCA_120 ZORRO_ID(MICRONIK, 0x0A, 0) - -#define ZORRO_MANUF_MICRONIK2 0x0F0F -#define ZORRO_PROD_MICRONIK2_Z3I ZORRO_ID(MICRONIK2, 0x01, 0) - -#define ZORRO_MANUF_MEGAMICRO 0x1000 -#define ZORRO_PROD_MEGAMICRO_SCRAM_500 ZORRO_ID(MEGAMICRO, 0x03, 0) -#define ZORRO_PROD_MEGAMICRO_SCRAM_500_RAM ZORRO_ID(MEGAMICRO, 0x04, 0) - -#define ZORRO_MANUF_IMTRONICS_2 0x1028 -#define ZORRO_PROD_IMTRONICS_HURRICANE_2800_3 ZORRO_ID(IMTRONICS_2, 0x39, 0) -#define ZORRO_PROD_IMTRONICS_HURRICANE_2800_4 ZORRO_ID(IMTRONICS_2, 0x57, 0) - -/* unofficial ID */ -#define ZORRO_MANUF_INDIVIDUAL_COMPUTERS 0x1212 -#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x00, 0) -#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x17, 0) -#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x2A, 0) - -#define ZORRO_MANUF_KUPKE_3 0x1248 -#define ZORRO_PROD_KUPKE_GOLEM_HD_3000 ZORRO_ID(KUPKE_3, 0x01, 0) - -#define ZORRO_MANUF_ITH 0x1388 -#define ZORRO_PROD_ITH_ISDN_MASTER_II ZORRO_ID(ITH, 0x01, 0) - -#define ZORRO_MANUF_VMC 0x1389 -#define ZORRO_PROD_VMC_ISDN_BLASTER_Z2 ZORRO_ID(VMC, 0x01, 0) -#define ZORRO_PROD_VMC_HYPERCOM_4 ZORRO_ID(VMC, 0x02, 0) - -#define ZORRO_MANUF_INFORMATION 0x157C -#define ZORRO_PROD_INFORMATION_ISDN_ENGINE_I ZORRO_ID(INFORMATION, 0x64, 0) - -#define ZORRO_MANUF_VORTEX 0x2017 -#define ZORRO_PROD_VORTEX_GOLDEN_GATE_80386SX ZORRO_ID(VORTEX, 0x07, 0) -#define ZORRO_PROD_VORTEX_GOLDEN_GATE_RAM ZORRO_ID(VORTEX, 0x08, 0) -#define ZORRO_PROD_VORTEX_GOLDEN_GATE_80486 ZORRO_ID(VORTEX, 0x09, 0) - -#define ZORRO_MANUF_EXPANSION_SYSTEMS 0x2062 -#define ZORRO_PROD_EXPANSION_SYSTEMS_DATAFLYER_4000SX ZORRO_ID(EXPANSION_SYSTEMS, 0x01, 0) -#define ZORRO_PROD_EXPANSION_SYSTEMS_DATAFLYER_4000SX_RAM ZORRO_ID(EXPANSION_SYSTEMS, 0x02, 0) - -#define ZORRO_MANUF_READYSOFT 0x2100 -#define ZORRO_PROD_READYSOFT_AMAX_II_IV ZORRO_ID(READYSOFT, 0x01, 0) - -#define ZORRO_MANUF_PHASE5 0x2140 -#define ZORRO_PROD_PHASE5_BLIZZARD_RAM ZORRO_ID(PHASE5, 0x01, 0) -#define ZORRO_PROD_PHASE5_BLIZZARD ZORRO_ID(PHASE5, 0x02, 0) -#define ZORRO_PROD_PHASE5_BLIZZARD_1220_IV ZORRO_ID(PHASE5, 0x06, 0) -#define ZORRO_PROD_PHASE5_FASTLANE_Z3_RAM ZORRO_ID(PHASE5, 0x0A, 0) -#define ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060 ZORRO_ID(PHASE5, 0x0B, 0) -#define ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM ZORRO_ID(PHASE5, 0x0C, 0) -#define ZORRO_PROD_PHASE5_BLIZZARD_1230 ZORRO_ID(PHASE5, 0x0D, 0) -#define ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260 ZORRO_ID(PHASE5, 0x11, 0) -#define ZORRO_PROD_PHASE5_BLIZZARD_2060 ZORRO_ID(PHASE5, 0x18, 0) -#define ZORRO_PROD_PHASE5_CYBERSTORM_MK_II ZORRO_ID(PHASE5, 0x19, 0) -#define ZORRO_PROD_PHASE5_CYBERVISION64 ZORRO_ID(PHASE5, 0x22, 0) -#define ZORRO_PROD_PHASE5_CYBERVISION64_3D_PROTOTYPE ZORRO_ID(PHASE5, 0x32, 0) -#define ZORRO_PROD_PHASE5_CYBERVISION64_3D ZORRO_ID(PHASE5, 0x43, 0) -#define ZORRO_PROD_PHASE5_CYBERSTORM_MK_III ZORRO_ID(PHASE5, 0x64, 0) -#define ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS ZORRO_ID(PHASE5, 0x6e, 0) - -#define ZORRO_MANUF_DPS 0x2169 -#define ZORRO_PROD_DPS_PERSONAL_ANIMATION_RECORDER ZORRO_ID(DPS, 0x01, 0) - -#define ZORRO_MANUF_APOLLO_2 0x2200 -#define ZORRO_PROD_APOLLO_A620_68020_1 ZORRO_ID(APOLLO_2, 0x00, 0) -#define ZORRO_PROD_APOLLO_A620_68020_2 ZORRO_ID(APOLLO_2, 0x01, 0) - -#define ZORRO_MANUF_APOLLO_3 0x2222 -#define ZORRO_PROD_APOLLO_AT_APOLLO ZORRO_ID(APOLLO_3, 0x22, 0) -#define ZORRO_PROD_APOLLO_1230_1240_1260_2030_4040_4060 ZORRO_ID(APOLLO_3, 0x23, 0) - -#define ZORRO_MANUF_PETSOFF_LP 0x38A5 -#define ZORRO_PROD_PETSOFF_LP_DELFINA ZORRO_ID(PETSOFF_LP, 0x00, 0) -#define ZORRO_PROD_PETSOFF_LP_DELFINA_LITE ZORRO_ID(PETSOFF_LP, 0x01, 0) - -#define ZORRO_MANUF_UWE_GERLACH 0x3FF7 -#define ZORRO_PROD_UWE_GERLACH_RAM_ROM ZORRO_ID(UWE_GERLACH, 0xd4, 0) - -#define ZORRO_MANUF_ACT 0x4231 -#define ZORRO_PROD_ACT_PRELUDE ZORRO_ID(ACT, 0x01, 0) - -#define ZORRO_MANUF_MACROSYSTEMS_GERMANY 0x4754 -#define ZORRO_PROD_MACROSYSTEMS_MAESTRO ZORRO_ID(MACROSYSTEMS_GERMANY, 0x03, 0) -#define ZORRO_PROD_MACROSYSTEMS_VLAB ZORRO_ID(MACROSYSTEMS_GERMANY, 0x04, 0) -#define ZORRO_PROD_MACROSYSTEMS_MAESTRO_PRO ZORRO_ID(MACROSYSTEMS_GERMANY, 0x05, 0) -#define ZORRO_PROD_MACROSYSTEMS_RETINA ZORRO_ID(MACROSYSTEMS_GERMANY, 0x06, 0) -#define ZORRO_PROD_MACROSYSTEMS_MULTI_EVOLUTION ZORRO_ID(MACROSYSTEMS_GERMANY, 0x08, 0) -#define ZORRO_PROD_MACROSYSTEMS_TOCCATA ZORRO_ID(MACROSYSTEMS_GERMANY, 0x0C, 0) -#define ZORRO_PROD_MACROSYSTEMS_RETINA_Z3 ZORRO_ID(MACROSYSTEMS_GERMANY, 0x10, 0) -#define ZORRO_PROD_MACROSYSTEMS_VLAB_MOTION ZORRO_ID(MACROSYSTEMS_GERMANY, 0x12, 0) -#define ZORRO_PROD_MACROSYSTEMS_ALTAIS ZORRO_ID(MACROSYSTEMS_GERMANY, 0x13, 0) -#define ZORRO_PROD_MACROSYSTEMS_FALCON_040 ZORRO_ID(MACROSYSTEMS_GERMANY, 0xFD, 0) - -#define ZORRO_MANUF_COMBITEC 0x6766 - -#define ZORRO_MANUF_SKI_PERIPHERALS 0x8000 -#define ZORRO_PROD_SKI_PERIPHERALS_MAST_FIREBALL ZORRO_ID(SKI_PERIPHERALS, 0x08, 0) -#define ZORRO_PROD_SKI_PERIPHERALS_SCSI_DUAL_SERIAL ZORRO_ID(SKI_PERIPHERALS, 0x80, 0) - -#define ZORRO_MANUF_REIS_WARE_2 0xA9AD -#define ZORRO_PROD_REIS_WARE_SCAN_KING ZORRO_ID(REIS_WARE_2, 0x11, 0) - -#define ZORRO_MANUF_CAMERON 0xAA01 -#define ZORRO_PROD_CAMERON_PERSONAL_A4 ZORRO_ID(CAMERON, 0x10, 0) - -#define ZORRO_MANUF_REIS_WARE 0xAA11 -#define ZORRO_PROD_REIS_WARE_HANDYSCANNER ZORRO_ID(REIS_WARE, 0x11, 0) - -#define ZORRO_MANUF_PHOENIX_2 0xB5A8 -#define ZORRO_PROD_PHOENIX_ST506_2 ZORRO_ID(PHOENIX_2, 0x21, 0) -#define ZORRO_PROD_PHOENIX_SCSI_2 ZORRO_ID(PHOENIX_2, 0x22, 0) -#define ZORRO_PROD_PHOENIX_RAM_2 ZORRO_ID(PHOENIX_2, 0xBE, 0) - -#define ZORRO_MANUF_COMBITEC_2 0xC008 -#define ZORRO_PROD_COMBITEC_HD ZORRO_ID(COMBITEC_2, 0x2A, 0) -#define ZORRO_PROD_COMBITEC_SRAM ZORRO_ID(COMBITEC_2, 0x2B, 0) - - - /* - * Test and illegal Manufacturer IDs. - */ - -#define ZORRO_MANUF_HACKER 0x07DB -#define ZORRO_PROD_GENERAL_PROTOTYPE ZORRO_ID(HACKER, 0x00, 0) -#define ZORRO_PROD_HACKER_SCSI ZORRO_ID(HACKER, 0x01, 0) -#define ZORRO_PROD_RESOURCE_MANAGEMENT_FORCE_QUICKNET_QN2000 ZORRO_ID(HACKER, 0x02, 0) -#define ZORRO_PROD_VECTOR_CONNECTION_2 ZORRO_ID(HACKER, 0xE0, 0) -#define ZORRO_PROD_VECTOR_CONNECTION_3 ZORRO_ID(HACKER, 0xE1, 0) -#define ZORRO_PROD_VECTOR_CONNECTION_4 ZORRO_ID(HACKER, 0xE2, 0) -#define ZORRO_PROD_VECTOR_CONNECTION_5 ZORRO_ID(HACKER, 0xE3, 0) diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 33d2b8fe166d..3ce25b5d75a9 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -426,3 +426,5 @@ header-y += x25.h header-y += xattr.h header-y += xfrm.h header-y += hw_breakpoint.h +header-y += zorro.h +header-y += zorro_ids.h diff --git a/include/uapi/linux/zorro.h b/include/uapi/linux/zorro.h new file mode 100644 index 000000000000..36a033e23d31 --- /dev/null +++ b/include/uapi/linux/zorro.h @@ -0,0 +1,113 @@ +/* + * linux/zorro.h -- Amiga AutoConfig (Zorro) Bus Definitions + * + * Copyright (C) 1995--2003 Geert Uytterhoeven + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive + * for more details. + */ + +#ifndef _UAPI_LINUX_ZORRO_H +#define _UAPI_LINUX_ZORRO_H + +#include + + + /* + * Each Zorro board has a 32-bit ID of the form + * + * mmmmmmmmmmmmmmmmppppppppeeeeeeee + * + * with + * + * mmmmmmmmmmmmmmmm 16-bit Manufacturer ID (assigned by CBM (sigh)) + * pppppppp 8-bit Product ID (assigned by manufacturer) + * eeeeeeee 8-bit Extended Product ID (currently only used + * for some GVP boards) + */ + + +#define ZORRO_MANUF(id) ((id) >> 16) +#define ZORRO_PROD(id) (((id) >> 8) & 0xff) +#define ZORRO_EPC(id) ((id) & 0xff) + +#define ZORRO_ID(manuf, prod, epc) \ + ((ZORRO_MANUF_##manuf << 16) | ((prod) << 8) | (epc)) + +typedef __u32 zorro_id; + + +/* Include the ID list */ +#include + + + /* + * GVP identifies most of its products through the 'extended product code' + * (epc). The epc has to be ANDed with the GVP_PRODMASK before the + * identification. + */ + +#define GVP_PRODMASK (0xf8) +#define GVP_SCSICLKMASK (0x01) + +enum GVP_flags { + GVP_IO = 0x01, + GVP_ACCEL = 0x02, + GVP_SCSI = 0x04, + GVP_24BITDMA = 0x08, + GVP_25BITDMA = 0x10, + GVP_NOBANK = 0x20, + GVP_14MHZ = 0x40, +}; + + +struct Node { + struct Node *ln_Succ; /* Pointer to next (successor) */ + struct Node *ln_Pred; /* Pointer to previous (predecessor) */ + __u8 ln_Type; + __s8 ln_Pri; /* Priority, for sorting */ + __s8 *ln_Name; /* ID string, null terminated */ +} __packed; + +struct ExpansionRom { + /* -First 16 bytes of the expansion ROM */ + __u8 er_Type; /* Board type, size and flags */ + __u8 er_Product; /* Product number, assigned by manufacturer */ + __u8 er_Flags; /* Flags */ + __u8 er_Reserved03; /* Must be zero ($ff inverted) */ + __u16 er_Manufacturer; /* Unique ID, ASSIGNED BY COMMODORE-AMIGA! */ + __u32 er_SerialNumber; /* Available for use by manufacturer */ + __u16 er_InitDiagVec; /* Offset to optional "DiagArea" structure */ + __u8 er_Reserved0c; + __u8 er_Reserved0d; + __u8 er_Reserved0e; + __u8 er_Reserved0f; +} __packed; + +/* er_Type board type bits */ +#define ERT_TYPEMASK 0xc0 +#define ERT_ZORROII 0xc0 +#define ERT_ZORROIII 0x80 + +/* other bits defined in er_Type */ +#define ERTB_MEMLIST 5 /* Link RAM into free memory list */ +#define ERTF_MEMLIST (1<<5) + +struct ConfigDev { + struct Node cd_Node; + __u8 cd_Flags; /* (read/write) */ + __u8 cd_Pad; /* reserved */ + struct ExpansionRom cd_Rom; /* copy of board's expansion ROM */ + void *cd_BoardAddr; /* where in memory the board was placed */ + __u32 cd_BoardSize; /* size of board in bytes */ + __u16 cd_SlotAddr; /* which slot number (PRIVATE) */ + __u16 cd_SlotSize; /* number of slots (PRIVATE) */ + void *cd_Driver; /* pointer to node of driver */ + struct ConfigDev *cd_NextCD; /* linked list of drivers to config */ + __u32 cd_Unused[4]; /* for whatever the driver wants */ +} __packed; + +#define ZORRO_NUM_AUTO 16 + +#endif /* _UAPI_LINUX_ZORRO_H */ diff --git a/include/uapi/linux/zorro_ids.h b/include/uapi/linux/zorro_ids.h new file mode 100644 index 000000000000..74bc53bcfdcf --- /dev/null +++ b/include/uapi/linux/zorro_ids.h @@ -0,0 +1,552 @@ +/* + * Zorro board IDs + * + * Please keep sorted. + */ + + +#define ZORRO_MANUF_PACIFIC_PERIPHERALS 0x00D3 +#define ZORRO_PROD_PACIFIC_PERIPHERALS_SE_2000_A500 ZORRO_ID(PACIFIC_PERIPHERALS, 0x00, 0) +#define ZORRO_PROD_PACIFIC_PERIPHERALS_SCSI ZORRO_ID(PACIFIC_PERIPHERALS, 0x0A, 0) + +#define ZORRO_MANUF_MACROSYSTEMS_USA_2 0x0100 +#define ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE ZORRO_ID(MACROSYSTEMS_USA_2, 0x13, 0) + +#define ZORRO_MANUF_KUPKE_1 0x00DD +#define ZORRO_PROD_KUPKE_GOLEM_RAM_BOX_2MB ZORRO_ID(KUPKE_1, 0x00, 0) + +#define ZORRO_MANUF_MEMPHIS 0x0100 +#define ZORRO_PROD_MEMPHIS_STORMBRINGER ZORRO_ID(MEMPHIS, 0x00, 0) + +#define ZORRO_MANUF_3_STATE 0x0200 +#define ZORRO_PROD_3_STATE_MEGAMIX_2000 ZORRO_ID(3_STATE, 0x02, 0) + +#define ZORRO_MANUF_COMMODORE_BRAUNSCHWEIG 0x0201 +#define ZORRO_PROD_CBM_A2088_A2286 ZORRO_ID(COMMODORE_BRAUNSCHWEIG, 0x01, 0) +#define ZORRO_PROD_CBM_A2286 ZORRO_ID(COMMODORE_BRAUNSCHWEIG, 0x02, 0) +#define ZORRO_PROD_CBM_A4091_1 ZORRO_ID(COMMODORE_BRAUNSCHWEIG, 0x54, 0) +#define ZORRO_PROD_CBM_A2386SX_1 ZORRO_ID(COMMODORE_BRAUNSCHWEIG, 0x67, 0) + +#define ZORRO_MANUF_COMMODORE_WEST_CHESTER_1 0x0202 +#define ZORRO_PROD_CBM_A2090A ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x01, 0) +#define ZORRO_PROD_CBM_A590_A2091_1 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x02, 0) +#define ZORRO_PROD_CBM_A590_A2091_2 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x03, 0) +#define ZORRO_PROD_CBM_A2090B ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x04, 0) +#define ZORRO_PROD_CBM_A2060 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x09, 0) +#define ZORRO_PROD_CBM_A590_A2052_A2058_A2091 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x0A, 0) +#define ZORRO_PROD_CBM_A560_RAM ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x20, 0) +#define ZORRO_PROD_CBM_A2232_PROTOTYPE ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x45, 0) +#define ZORRO_PROD_CBM_A2232 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x46, 0) +#define ZORRO_PROD_CBM_A2620 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x50, 0) +#define ZORRO_PROD_CBM_A2630 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x51, 0) +#define ZORRO_PROD_CBM_A4091_2 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x54, 0) +#define ZORRO_PROD_CBM_A2065_1 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x5A, 0) +#define ZORRO_PROD_CBM_ROMULATOR ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x60, 0) +#define ZORRO_PROD_CBM_A3000_TEST_FIXTURE ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x61, 0) +#define ZORRO_PROD_CBM_A2386SX_2 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x67, 0) +#define ZORRO_PROD_CBM_A2065_2 ZORRO_ID(COMMODORE_WEST_CHESTER_1, 0x70, 0) + +#define ZORRO_MANUF_COMMODORE_WEST_CHESTER_2 0x0203 +#define ZORRO_PROD_CBM_A2090A_CM ZORRO_ID(COMMODORE_WEST_CHESTER_2, 0x03, 0) + +#define ZORRO_MANUF_PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2 0x02F4 +#define ZORRO_PROD_PPS_EXP8000 ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS_2, 0x02, 0) + +#define ZORRO_MANUF_KOLFF_COMPUTER_SUPPLIES 0x02FF +#define ZORRO_PROD_KCS_POWER_PC_BOARD ZORRO_ID(KOLFF_COMPUTER_SUPPLIES, 0x00, 0) + +#define ZORRO_MANUF_CARDCO_1 0x03EC +#define ZORRO_PROD_CARDCO_KRONOS_2000_1 ZORRO_ID(CARDCO_1, 0x04, 0) +#define ZORRO_PROD_CARDCO_A1000_1 ZORRO_ID(CARDCO_1, 0x0C, 0) +#define ZORRO_PROD_CARDCO_ESCORT ZORRO_ID(CARDCO_1, 0x0E, 0) +#define ZORRO_PROD_CARDCO_A2410 ZORRO_ID(CARDCO_1, 0xF5, 0) + +#define ZORRO_MANUF_A_SQUARED 0x03ED +#define ZORRO_PROD_A_SQUARED_LIVE_2000 ZORRO_ID(A_SQUARED, 0x01, 0) + +#define ZORRO_MANUF_COMSPEC_COMMUNICATIONS 0x03EE +#define ZORRO_PROD_COMSPEC_COMMUNICATIONS_AX2000 ZORRO_ID(COMSPEC_COMMUNICATIONS, 0x01, 0) + +#define ZORRO_MANUF_ANAKIN_RESEARCH 0x03F1 +#define ZORRO_PROD_ANAKIN_RESEARCH_EASYL ZORRO_ID(ANAKIN_RESEARCH, 0x01, 0) + +#define ZORRO_MANUF_MICROBOTICS 0x03F2 +#define ZORRO_PROD_MICROBOTICS_STARBOARD_II ZORRO_ID(MICROBOTICS, 0x00, 0) +#define ZORRO_PROD_MICROBOTICS_STARDRIVE ZORRO_ID(MICROBOTICS, 0x02, 0) +#define ZORRO_PROD_MICROBOTICS_8_UP_A ZORRO_ID(MICROBOTICS, 0x03, 0) +#define ZORRO_PROD_MICROBOTICS_8_UP_Z ZORRO_ID(MICROBOTICS, 0x04, 0) +#define ZORRO_PROD_MICROBOTICS_DELTA_RAM ZORRO_ID(MICROBOTICS, 0x20, 0) +#define ZORRO_PROD_MICROBOTICS_8_STAR_RAM ZORRO_ID(MICROBOTICS, 0x40, 0) +#define ZORRO_PROD_MICROBOTICS_8_STAR ZORRO_ID(MICROBOTICS, 0x41, 0) +#define ZORRO_PROD_MICROBOTICS_VXL_RAM_32 ZORRO_ID(MICROBOTICS, 0x44, 0) +#define ZORRO_PROD_MICROBOTICS_VXL_68030 ZORRO_ID(MICROBOTICS, 0x45, 0) +#define ZORRO_PROD_MICROBOTICS_DELTA ZORRO_ID(MICROBOTICS, 0x60, 0) +#define ZORRO_PROD_MICROBOTICS_MBX_1200_1200Z_RAM ZORRO_ID(MICROBOTICS, 0x81, 0) +#define ZORRO_PROD_MICROBOTICS_HARDFRAME_2000_1 ZORRO_ID(MICROBOTICS, 0x96, 0) +#define ZORRO_PROD_MICROBOTICS_HARDFRAME_2000_2 ZORRO_ID(MICROBOTICS, 0x9E, 0) +#define ZORRO_PROD_MICROBOTICS_MBX_1200_1200Z ZORRO_ID(MICROBOTICS, 0xC1, 0) + +#define ZORRO_MANUF_ACCESS_ASSOCIATES_ALEGRA 0x03F4 + +#define ZORRO_MANUF_EXPANSION_TECHNOLOGIES 0x03F6 + +#define ZORRO_MANUF_ASDG 0x03FF +#define ZORRO_PROD_ASDG_MEMORY_1 ZORRO_ID(ASDG, 0x01, 0) +#define ZORRO_PROD_ASDG_MEMORY_2 ZORRO_ID(ASDG, 0x02, 0) +#define ZORRO_PROD_ASDG_EB920_LAN_ROVER ZORRO_ID(ASDG, 0xFE, 0) +#define ZORRO_PROD_ASDG_GPIB_DUALIEEE488_TWIN_X ZORRO_ID(ASDG, 0xFF, 0) + +#define ZORRO_MANUF_IMTRONICS_1 0x0404 +#define ZORRO_PROD_IMTRONICS_HURRICANE_2800_1 ZORRO_ID(IMTRONICS_1, 0x39, 0) +#define ZORRO_PROD_IMTRONICS_HURRICANE_2800_2 ZORRO_ID(IMTRONICS_1, 0x57, 0) + +#define ZORRO_MANUF_CBM_UNIVERSITY_OF_LOWELL 0x0406 +#define ZORRO_PROD_CBM_A2410 ZORRO_ID(CBM_UNIVERSITY_OF_LOWELL, 0x00, 0) + +#define ZORRO_MANUF_AMERISTAR 0x041D +#define ZORRO_PROD_AMERISTAR_A2065 ZORRO_ID(AMERISTAR, 0x01, 0) +#define ZORRO_PROD_AMERISTAR_A560 ZORRO_ID(AMERISTAR, 0x09, 0) +#define ZORRO_PROD_AMERISTAR_A4066 ZORRO_ID(AMERISTAR, 0x0A, 0) + +#define ZORRO_MANUF_SUPRA 0x0420 +#define ZORRO_PROD_SUPRA_SUPRADRIVE_4x4 ZORRO_ID(SUPRA, 0x01, 0) +#define ZORRO_PROD_SUPRA_1000_RAM ZORRO_ID(SUPRA, 0x02, 0) +#define ZORRO_PROD_SUPRA_2000_DMA ZORRO_ID(SUPRA, 0x03, 0) +#define ZORRO_PROD_SUPRA_500 ZORRO_ID(SUPRA, 0x05, 0) +#define ZORRO_PROD_SUPRA_500_SCSI ZORRO_ID(SUPRA, 0x08, 0) +#define ZORRO_PROD_SUPRA_500XP_2000_RAM ZORRO_ID(SUPRA, 0x09, 0) +#define ZORRO_PROD_SUPRA_500RX_2000_RAM ZORRO_ID(SUPRA, 0x0A, 0) +#define ZORRO_PROD_SUPRA_2400ZI ZORRO_ID(SUPRA, 0x0B, 0) +#define ZORRO_PROD_SUPRA_500XP_SUPRADRIVE_WORDSYNC ZORRO_ID(SUPRA, 0x0C, 0) +#define ZORRO_PROD_SUPRA_SUPRADRIVE_WORDSYNC_II ZORRO_ID(SUPRA, 0x0D, 0) +#define ZORRO_PROD_SUPRA_2400ZIPLUS ZORRO_ID(SUPRA, 0x10, 0) + +#define ZORRO_MANUF_COMPUTER_SYSTEMS_ASSOCIATES 0x0422 +#define ZORRO_PROD_CSA_MAGNUM ZORRO_ID(COMPUTER_SYSTEMS_ASSOCIATES, 0x11, 0) +#define ZORRO_PROD_CSA_12_GAUGE ZORRO_ID(COMPUTER_SYSTEMS_ASSOCIATES, 0x15, 0) + +#define ZORRO_MANUF_MARC_MICHAEL_GROTH 0x0439 + +#define ZORRO_MANUF_M_TECH 0x0502 +#define ZORRO_PROD_MTEC_AT500_1 ZORRO_ID(M_TECH, 0x03, 0) + +#define ZORRO_MANUF_GREAT_VALLEY_PRODUCTS_1 0x06E1 +#define ZORRO_PROD_GVP_IMPACT_SERIES_I ZORRO_ID(GREAT_VALLEY_PRODUCTS_1, 0x08, 0) + +#define ZORRO_MANUF_BYTEBOX 0x07DA +#define ZORRO_PROD_BYTEBOX_A500 ZORRO_ID(BYTEBOX, 0x00, 0) + +#define ZORRO_MANUF_DKB_POWER_COMPUTING 0x07DC +#define ZORRO_PROD_DKB_POWER_COMPUTING_SECUREKEY ZORRO_ID(DKB_POWER_COMPUTING, 0x09, 0) +#define ZORRO_PROD_DKB_POWER_COMPUTING_DKM_3128 ZORRO_ID(DKB_POWER_COMPUTING, 0x0E, 0) +#define ZORRO_PROD_DKB_POWER_COMPUTING_RAPID_FIRE ZORRO_ID(DKB_POWER_COMPUTING, 0x0F, 0) +#define ZORRO_PROD_DKB_POWER_COMPUTING_DKM_1202 ZORRO_ID(DKB_POWER_COMPUTING, 0x10, 0) +#define ZORRO_PROD_DKB_POWER_COMPUTING_COBRA_VIPER_II_68EC030 ZORRO_ID(DKB_POWER_COMPUTING, 0x12, 0) +#define ZORRO_PROD_DKB_POWER_COMPUTING_WILDFIRE_060_1 ZORRO_ID(DKB_POWER_COMPUTING, 0x17, 0) +#define ZORRO_PROD_DKB_POWER_COMPUTING_WILDFIRE_060_2 ZORRO_ID(DKB_POWER_COMPUTING, 0xFF, 0) + +#define ZORRO_MANUF_GREAT_VALLEY_PRODUCTS_2 0x07E1 +#define ZORRO_PROD_GVP_IMPACT_SERIES_I_4K ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x01, 0) +#define ZORRO_PROD_GVP_IMPACT_SERIES_I_16K_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x02, 0) +#define ZORRO_PROD_GVP_IMPACT_SERIES_I_16K_3 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x03, 0) +#define ZORRO_PROD_GVP_IMPACT_3001_IDE_1 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x08, 0) +#define ZORRO_PROD_GVP_IMPACT_3001_RAM ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x09, 0) +#define ZORRO_PROD_GVP_IMPACT_SERIES_II_RAM_1 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0A, 0) +#define ZORRO_PROD_GVP_EPC_BASE ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0) +#define ZORRO_PROD_GVP_GFORCE_040_1 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x20) +#define ZORRO_PROD_GVP_GFORCE_040_SCSI_1 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x30) +#define ZORRO_PROD_GVP_A1291 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x40) +#define ZORRO_PROD_GVP_COMBO_030_R4 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x60) +#define ZORRO_PROD_GVP_COMBO_030_R4_SCSI ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x70) +#define ZORRO_PROD_GVP_PHONEPAK ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x78) +#define ZORRO_PROD_GVP_IO_EXTENDER ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0x98) +#define ZORRO_PROD_GVP_GFORCE_030 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xa0) +#define ZORRO_PROD_GVP_GFORCE_030_SCSI ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xb0) +#define ZORRO_PROD_GVP_A530 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xc0) +#define ZORRO_PROD_GVP_A530_SCSI ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xd0) +#define ZORRO_PROD_GVP_COMBO_030_R3 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xe0) +#define ZORRO_PROD_GVP_COMBO_030_R3_SCSI ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xf0) +#define ZORRO_PROD_GVP_SERIES_II ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0B, 0xf8) +#define ZORRO_PROD_GVP_IMPACT_3001_IDE_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0D, 0) +/*#define ZORRO_PROD_GVP_A2000_030 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0D, 0)*/ +/*#define ZORRO_PROD_GVP_GFORCE_040_SCSI_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x0D, 0)*/ +#define ZORRO_PROD_GVP_GFORCE_040_060 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x16, 0) +#define ZORRO_PROD_GVP_IMPACT_VISION_24 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0x20, 0) +#define ZORRO_PROD_GVP_GFORCE_040_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_2, 0xFF, 0) + +#define ZORRO_MANUF_CALIFORNIA_ACCESS_SYNERGY 0x07E5 +#define ZORRO_PROD_CALIFORNIA_ACCESS_SYNERGY_MALIBU ZORRO_ID(CALIFORNIA_ACCESS_SYNERGY, 0x01, 0) + +#define ZORRO_MANUF_XETEC 0x07E6 +#define ZORRO_PROD_XETEC_FASTCARD ZORRO_ID(XETEC, 0x01, 0) +#define ZORRO_PROD_XETEC_FASTCARD_RAM ZORRO_ID(XETEC, 0x02, 0) +#define ZORRO_PROD_XETEC_FASTCARD_PLUS ZORRO_ID(XETEC, 0x03, 0) + +#define ZORRO_MANUF_PROGRESSIVE_PERIPHERALS_AND_SYSTEMS 0x07EA +#define ZORRO_PROD_PPS_MERCURY ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0x00, 0) +#define ZORRO_PROD_PPS_A3000_68040 ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0x01, 0) +#define ZORRO_PROD_PPS_A2000_68040 ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0x69, 0) +#define ZORRO_PROD_PPS_ZEUS ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0x96, 0) +#define ZORRO_PROD_PPS_A500_68040 ZORRO_ID(PROGRESSIVE_PERIPHERALS_AND_SYSTEMS, 0xBB, 0) + +#define ZORRO_MANUF_XEBEC 0x07EC + +#define ZORRO_MANUF_SPIRIT_TECHNOLOGY 0x07F2 +#define ZORRO_PROD_SPIRIT_TECHNOLOGY_INSIDER_IN1000 ZORRO_ID(SPIRIT_TECHNOLOGY, 0x01, 0) +#define ZORRO_PROD_SPIRIT_TECHNOLOGY_INSIDER_IN500 ZORRO_ID(SPIRIT_TECHNOLOGY, 0x02, 0) +#define ZORRO_PROD_SPIRIT_TECHNOLOGY_SIN500 ZORRO_ID(SPIRIT_TECHNOLOGY, 0x03, 0) +#define ZORRO_PROD_SPIRIT_TECHNOLOGY_HDA_506 ZORRO_ID(SPIRIT_TECHNOLOGY, 0x04, 0) +#define ZORRO_PROD_SPIRIT_TECHNOLOGY_AX_S ZORRO_ID(SPIRIT_TECHNOLOGY, 0x05, 0) +#define ZORRO_PROD_SPIRIT_TECHNOLOGY_OCTABYTE ZORRO_ID(SPIRIT_TECHNOLOGY, 0x06, 0) +#define ZORRO_PROD_SPIRIT_TECHNOLOGY_INMATE ZORRO_ID(SPIRIT_TECHNOLOGY, 0x08, 0) + +#define ZORRO_MANUF_SPIRIT_TECHNOLOGY_2 0x07F3 + +#define ZORRO_MANUF_BSC_ALFADATA_1 0x07FE +#define ZORRO_PROD_BSC_ALF_3_1 ZORRO_ID(BSC_ALFADATA_1, 0x03, 0) + +#define ZORRO_MANUF_BSC_ALFADATA_2 0x0801 +#define ZORRO_PROD_BSC_ALF_2_1 ZORRO_ID(BSC_ALFADATA_2, 0x01, 0) +#define ZORRO_PROD_BSC_ALF_2_2 ZORRO_ID(BSC_ALFADATA_2, 0x02, 0) +#define ZORRO_PROD_BSC_ALF_3_2 ZORRO_ID(BSC_ALFADATA_2, 0x03, 0) + +#define ZORRO_MANUF_CARDCO_2 0x0802 +#define ZORRO_PROD_CARDCO_KRONOS_2000_2 ZORRO_ID(CARDCO_2, 0x04, 0) +#define ZORRO_PROD_CARDCO_A1000_2 ZORRO_ID(CARDCO_2, 0x0C, 0) + +#define ZORRO_MANUF_JOCHHEIM 0x0804 +#define ZORRO_PROD_JOCHHEIM_RAM ZORRO_ID(JOCHHEIM, 0x01, 0) + +#define ZORRO_MANUF_CHECKPOINT_TECHNOLOGIES 0x0807 +#define ZORRO_PROD_CHECKPOINT_TECHNOLOGIES_SERIAL_SOLUTION ZORRO_ID(CHECKPOINT_TECHNOLOGIES, 0x00, 0) + +#define ZORRO_MANUF_EDOTRONIK 0x0810 +#define ZORRO_PROD_EDOTRONIK_IEEE_488 ZORRO_ID(EDOTRONIK, 0x01, 0) +#define ZORRO_PROD_EDOTRONIK_8032 ZORRO_ID(EDOTRONIK, 0x02, 0) +#define ZORRO_PROD_EDOTRONIK_MULTISERIAL ZORRO_ID(EDOTRONIK, 0x03, 0) +#define ZORRO_PROD_EDOTRONIK_VIDEODIGITIZER ZORRO_ID(EDOTRONIK, 0x04, 0) +#define ZORRO_PROD_EDOTRONIK_PARALLEL_IO ZORRO_ID(EDOTRONIK, 0x05, 0) +#define ZORRO_PROD_EDOTRONIK_PIC_PROTOYPING ZORRO_ID(EDOTRONIK, 0x06, 0) +#define ZORRO_PROD_EDOTRONIK_ADC ZORRO_ID(EDOTRONIK, 0x07, 0) +#define ZORRO_PROD_EDOTRONIK_VME ZORRO_ID(EDOTRONIK, 0x08, 0) +#define ZORRO_PROD_EDOTRONIK_DSP96000 ZORRO_ID(EDOTRONIK, 0x09, 0) + +#define ZORRO_MANUF_NES_INC 0x0813 +#define ZORRO_PROD_NES_INC_RAM ZORRO_ID(NES_INC, 0x00, 0) + +#define ZORRO_MANUF_ICD 0x0817 +#define ZORRO_PROD_ICD_ADVANTAGE_2000_SCSI ZORRO_ID(ICD, 0x01, 0) +#define ZORRO_PROD_ICD_ADVANTAGE_IDE ZORRO_ID(ICD, 0x03, 0) +#define ZORRO_PROD_ICD_ADVANTAGE_2080_RAM ZORRO_ID(ICD, 0x04, 0) + +#define ZORRO_MANUF_KUPKE_2 0x0819 +#define ZORRO_PROD_KUPKE_OMTI ZORRO_ID(KUPKE_2, 0x01, 0) +#define ZORRO_PROD_KUPKE_SCSI_II ZORRO_ID(KUPKE_2, 0x02, 0) +#define ZORRO_PROD_KUPKE_GOLEM_BOX ZORRO_ID(KUPKE_2, 0x03, 0) +#define ZORRO_PROD_KUPKE_030_882 ZORRO_ID(KUPKE_2, 0x04, 0) +#define ZORRO_PROD_KUPKE_SCSI_AT ZORRO_ID(KUPKE_2, 0x05, 0) + +#define ZORRO_MANUF_GREAT_VALLEY_PRODUCTS_3 0x081D +#define ZORRO_PROD_GVP_A2000_RAM8 ZORRO_ID(GREAT_VALLEY_PRODUCTS_3, 0x09, 0) +#define ZORRO_PROD_GVP_IMPACT_SERIES_II_RAM_2 ZORRO_ID(GREAT_VALLEY_PRODUCTS_3, 0x0A, 0) + +#define ZORRO_MANUF_INTERWORKS_NETWORK 0x081E + +#define ZORRO_MANUF_HARDITAL_SYNTHESIS 0x0820 +#define ZORRO_PROD_HARDITAL_SYNTHESIS_TQM_68030_68882 ZORRO_ID(HARDITAL_SYNTHESIS, 0x14, 0) + +#define ZORRO_MANUF_APPLIED_ENGINEERING 0x0828 +#define ZORRO_PROD_APPLIED_ENGINEERING_DL2000 ZORRO_ID(APPLIED_ENGINEERING, 0x10, 0) +#define ZORRO_PROD_APPLIED_ENGINEERING_RAM_WORKS ZORRO_ID(APPLIED_ENGINEERING, 0xE0, 0) + +#define ZORRO_MANUF_BSC_ALFADATA_3 0x082C +#define ZORRO_PROD_BSC_OKTAGON_2008 ZORRO_ID(BSC_ALFADATA_3, 0x05, 0) +#define ZORRO_PROD_BSC_TANDEM_AT_2008_508 ZORRO_ID(BSC_ALFADATA_3, 0x06, 0) +#define ZORRO_PROD_BSC_ALFA_RAM_1200 ZORRO_ID(BSC_ALFADATA_3, 0x07, 0) +#define ZORRO_PROD_BSC_OKTAGON_2008_RAM ZORRO_ID(BSC_ALFADATA_3, 0x08, 0) +#define ZORRO_PROD_BSC_MULTIFACE_I ZORRO_ID(BSC_ALFADATA_3, 0x10, 0) +#define ZORRO_PROD_BSC_MULTIFACE_II ZORRO_ID(BSC_ALFADATA_3, 0x11, 0) +#define ZORRO_PROD_BSC_MULTIFACE_III ZORRO_ID(BSC_ALFADATA_3, 0x12, 0) +#define ZORRO_PROD_BSC_FRAMEMASTER_II ZORRO_ID(BSC_ALFADATA_3, 0x20, 0) +#define ZORRO_PROD_BSC_GRAFFITI_RAM ZORRO_ID(BSC_ALFADATA_3, 0x21, 0) +#define ZORRO_PROD_BSC_GRAFFITI_REG ZORRO_ID(BSC_ALFADATA_3, 0x22, 0) +#define ZORRO_PROD_BSC_ISDN_MASTERCARD ZORRO_ID(BSC_ALFADATA_3, 0x40, 0) +#define ZORRO_PROD_BSC_ISDN_MASTERCARD_II ZORRO_ID(BSC_ALFADATA_3, 0x41, 0) + +#define ZORRO_MANUF_PHOENIX 0x0835 +#define ZORRO_PROD_PHOENIX_ST506 ZORRO_ID(PHOENIX, 0x21, 0) +#define ZORRO_PROD_PHOENIX_SCSI ZORRO_ID(PHOENIX, 0x22, 0) +#define ZORRO_PROD_PHOENIX_RAM ZORRO_ID(PHOENIX, 0xBE, 0) + +#define ZORRO_MANUF_ADVANCED_STORAGE_SYSTEMS 0x0836 +#define ZORRO_PROD_ADVANCED_STORAGE_SYSTEMS_NEXUS ZORRO_ID(ADVANCED_STORAGE_SYSTEMS, 0x01, 0) +#define ZORRO_PROD_ADVANCED_STORAGE_SYSTEMS_NEXUS_RAM ZORRO_ID(ADVANCED_STORAGE_SYSTEMS, 0x08, 0) + +#define ZORRO_MANUF_IMPULSE 0x0838 +#define ZORRO_PROD_IMPULSE_FIRECRACKER_24 ZORRO_ID(IMPULSE, 0x00, 0) + +#define ZORRO_MANUF_IVS 0x0840 +#define ZORRO_PROD_IVS_GRANDSLAM_PIC_2 ZORRO_ID(IVS, 0x02, 0) +#define ZORRO_PROD_IVS_GRANDSLAM_PIC_1 ZORRO_ID(IVS, 0x04, 0) +#define ZORRO_PROD_IVS_OVERDRIVE ZORRO_ID(IVS, 0x10, 0) +#define ZORRO_PROD_IVS_TRUMPCARD_CLASSIC ZORRO_ID(IVS, 0x30, 0) +#define ZORRO_PROD_IVS_TRUMPCARD_PRO_GRANDSLAM ZORRO_ID(IVS, 0x34, 0) +#define ZORRO_PROD_IVS_META_4 ZORRO_ID(IVS, 0x40, 0) +#define ZORRO_PROD_IVS_WAVETOOLS ZORRO_ID(IVS, 0xBF, 0) +#define ZORRO_PROD_IVS_VECTOR_1 ZORRO_ID(IVS, 0xF3, 0) +#define ZORRO_PROD_IVS_VECTOR_2 ZORRO_ID(IVS, 0xF4, 0) + +#define ZORRO_MANUF_VECTOR_1 0x0841 +#define ZORRO_PROD_VECTOR_CONNECTION_1 ZORRO_ID(VECTOR_1, 0xE3, 0) + +#define ZORRO_MANUF_XPERT_PRODEV 0x0845 +#define ZORRO_PROD_XPERT_PRODEV_VISIONA_RAM ZORRO_ID(XPERT_PRODEV, 0x01, 0) +#define ZORRO_PROD_XPERT_PRODEV_VISIONA_REG ZORRO_ID(XPERT_PRODEV, 0x02, 0) +#define ZORRO_PROD_XPERT_PRODEV_MERLIN_RAM ZORRO_ID(XPERT_PRODEV, 0x03, 0) +#define ZORRO_PROD_XPERT_PRODEV_MERLIN_REG_1 ZORRO_ID(XPERT_PRODEV, 0x04, 0) +#define ZORRO_PROD_XPERT_PRODEV_MERLIN_REG_2 ZORRO_ID(XPERT_PRODEV, 0xC9, 0) + +#define ZORRO_MANUF_HYDRA_SYSTEMS 0x0849 +#define ZORRO_PROD_HYDRA_SYSTEMS_AMIGANET ZORRO_ID(HYDRA_SYSTEMS, 0x01, 0) + +#define ZORRO_MANUF_SUNRIZE_INDUSTRIES 0x084F +#define ZORRO_PROD_SUNRIZE_INDUSTRIES_AD1012 ZORRO_ID(SUNRIZE_INDUSTRIES, 0x01, 0) +#define ZORRO_PROD_SUNRIZE_INDUSTRIES_AD516 ZORRO_ID(SUNRIZE_INDUSTRIES, 0x02, 0) +#define ZORRO_PROD_SUNRIZE_INDUSTRIES_DD512 ZORRO_ID(SUNRIZE_INDUSTRIES, 0x03, 0) + +#define ZORRO_MANUF_TRICERATOPS 0x0850 +#define ZORRO_PROD_TRICERATOPS_MULTI_IO ZORRO_ID(TRICERATOPS, 0x01, 0) + +#define ZORRO_MANUF_APPLIED_MAGIC 0x0851 +#define ZORRO_PROD_APPLIED_MAGIC_DMI_RESOLVER ZORRO_ID(APPLIED_MAGIC, 0x01, 0) +#define ZORRO_PROD_APPLIED_MAGIC_DIGITAL_BROADCASTER ZORRO_ID(APPLIED_MAGIC, 0x06, 0) + +#define ZORRO_MANUF_GFX_BASE 0x085E +#define ZORRO_PROD_GFX_BASE_GDA_1_VRAM ZORRO_ID(GFX_BASE, 0x00, 0) +#define ZORRO_PROD_GFX_BASE_GDA_1 ZORRO_ID(GFX_BASE, 0x01, 0) + +#define ZORRO_MANUF_ROCTEC 0x0860 +#define ZORRO_PROD_ROCTEC_RH_800C ZORRO_ID(ROCTEC, 0x01, 0) +#define ZORRO_PROD_ROCTEC_RH_800C_RAM ZORRO_ID(ROCTEC, 0x01, 0) + +#define ZORRO_MANUF_KATO 0x0861 +#define ZORRO_PROD_KATO_MELODY ZORRO_ID(KATO, 0x80, 0) +/* ID clash!! */ +#define ZORRO_MANUF_HELFRICH_1 0x0861 +#define ZORRO_PROD_HELFRICH_RAINBOW_II ZORRO_ID(HELFRICH_1, 0x20, 0) +#define ZORRO_PROD_HELFRICH_RAINBOW_III ZORRO_ID(HELFRICH_1, 0x21, 0) + +#define ZORRO_MANUF_ATLANTIS 0x0862 + +#define ZORRO_MANUF_PROTAR 0x0864 + +#define ZORRO_MANUF_ACS 0x0865 + +#define ZORRO_MANUF_SOFTWARE_RESULTS_ENTERPRISES 0x0866 +#define ZORRO_PROD_SOFTWARE_RESULTS_ENTERPRISES_GOLDEN_GATE_2_BUS_PLUS ZORRO_ID(SOFTWARE_RESULTS_ENTERPRISES, 0x01, 0) + +#define ZORRO_MANUF_MASOBOSHI 0x086D +#define ZORRO_PROD_MASOBOSHI_MASTER_CARD_SC201 ZORRO_ID(MASOBOSHI, 0x03, 0) +#define ZORRO_PROD_MASOBOSHI_MASTER_CARD_MC702 ZORRO_ID(MASOBOSHI, 0x04, 0) +#define ZORRO_PROD_MASOBOSHI_MVD_819 ZORRO_ID(MASOBOSHI, 0x07, 0) + +#define ZORRO_MANUF_MAINHATTAN_DATA 0x086F +#define ZORRO_PROD_MAINHATTAN_DATA_IDE ZORRO_ID(MAINHATTAN_DATA, 0x01, 0) + +#define ZORRO_MANUF_VILLAGE_TRONIC 0x0877 +#define ZORRO_PROD_VILLAGE_TRONIC_DOMINO_RAM ZORRO_ID(VILLAGE_TRONIC, 0x01, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_DOMINO_REG ZORRO_ID(VILLAGE_TRONIC, 0x02, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_DOMINO_16M_PROTOTYPE ZORRO_ID(VILLAGE_TRONIC, 0x03, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_RAM ZORRO_ID(VILLAGE_TRONIC, 0x0B, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_REG ZORRO_ID(VILLAGE_TRONIC, 0x0C, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_II_II_PLUS_SEGMENTED_MODE ZORRO_ID(VILLAGE_TRONIC, 0x0D, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM1 ZORRO_ID(VILLAGE_TRONIC, 0x15, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_RAM2 ZORRO_ID(VILLAGE_TRONIC, 0x16, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z2_REG ZORRO_ID(VILLAGE_TRONIC, 0x17, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_PICASSO_IV_Z3 ZORRO_ID(VILLAGE_TRONIC, 0x18, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_ARIADNE ZORRO_ID(VILLAGE_TRONIC, 0xC9, 0) +#define ZORRO_PROD_VILLAGE_TRONIC_ARIADNE2 ZORRO_ID(VILLAGE_TRONIC, 0xCA, 0) + +#define ZORRO_MANUF_UTILITIES_UNLIMITED 0x087B +#define ZORRO_PROD_UTILITIES_UNLIMITED_EMPLANT_DELUXE ZORRO_ID(UTILITIES_UNLIMITED, 0x15, 0) +#define ZORRO_PROD_UTILITIES_UNLIMITED_EMPLANT_DELUXE2 ZORRO_ID(UTILITIES_UNLIMITED, 0x20, 0) + +#define ZORRO_MANUF_AMITRIX 0x0880 +#define ZORRO_PROD_AMITRIX_MULTI_IO ZORRO_ID(AMITRIX, 0x01, 0) +#define ZORRO_PROD_AMITRIX_CD_RAM ZORRO_ID(AMITRIX, 0x02, 0) + +#define ZORRO_MANUF_ARMAX 0x0885 +#define ZORRO_PROD_ARMAX_OMNIBUS ZORRO_ID(ARMAX, 0x00, 0) + +#define ZORRO_MANUF_ZEUS 0x088D +#define ZORRO_PROD_ZEUS_SPIDER ZORRO_ID(ZEUS, 0x04, 0) + +#define ZORRO_MANUF_NEWTEK 0x088F +#define ZORRO_PROD_NEWTEK_VIDEOTOASTER ZORRO_ID(NEWTEK, 0x00, 0) + +#define ZORRO_MANUF_M_TECH_GERMANY 0x0890 +#define ZORRO_PROD_MTEC_AT500_2 ZORRO_ID(M_TECH_GERMANY, 0x01, 0) +#define ZORRO_PROD_MTEC_68030 ZORRO_ID(M_TECH_GERMANY, 0x03, 0) +#define ZORRO_PROD_MTEC_68020I ZORRO_ID(M_TECH_GERMANY, 0x06, 0) +#define ZORRO_PROD_MTEC_A1200_T68030_RTC ZORRO_ID(M_TECH_GERMANY, 0x20, 0) +#define ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530 ZORRO_ID(M_TECH_GERMANY, 0x21, 0) +#define ZORRO_PROD_MTEC_8_MB_RAM ZORRO_ID(M_TECH_GERMANY, 0x22, 0) +#define ZORRO_PROD_MTEC_VIPER_MK_V_E_MATRIX_530_SCSI_IDE ZORRO_ID(M_TECH_GERMANY, 0x24, 0) + +#define ZORRO_MANUF_GREAT_VALLEY_PRODUCTS_4 0x0891 +#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_RAM ZORRO_ID(GREAT_VALLEY_PRODUCTS_4, 0x01, 0) +#define ZORRO_PROD_GVP_EGS_28_24_SPECTRUM_REG ZORRO_ID(GREAT_VALLEY_PRODUCTS_4, 0x02, 0) + +#define ZORRO_MANUF_APOLLO_1 0x0892 +#define ZORRO_PROD_APOLLO_A1200 ZORRO_ID(APOLLO_1, 0x01, 0) + +#define ZORRO_MANUF_HELFRICH_2 0x0893 +#define ZORRO_PROD_HELFRICH_PICCOLO_RAM ZORRO_ID(HELFRICH_2, 0x05, 0) +#define ZORRO_PROD_HELFRICH_PICCOLO_REG ZORRO_ID(HELFRICH_2, 0x06, 0) +#define ZORRO_PROD_HELFRICH_PEGGY_PLUS_MPEG ZORRO_ID(HELFRICH_2, 0x07, 0) +#define ZORRO_PROD_HELFRICH_VIDEOCRUNCHER ZORRO_ID(HELFRICH_2, 0x08, 0) +#define ZORRO_PROD_HELFRICH_SD64_RAM ZORRO_ID(HELFRICH_2, 0x0A, 0) +#define ZORRO_PROD_HELFRICH_SD64_REG ZORRO_ID(HELFRICH_2, 0x0B, 0) + +#define ZORRO_MANUF_MACROSYSTEMS_USA 0x089B +#define ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx ZORRO_ID(MACROSYSTEMS_USA, 0x13, 0) + +#define ZORRO_MANUF_ELBOX_COMPUTER 0x089E +#define ZORRO_PROD_ELBOX_COMPUTER_1200_4 ZORRO_ID(ELBOX_COMPUTER, 0x06, 0) + +#define ZORRO_MANUF_HARMS_PROFESSIONAL 0x0A00 +#define ZORRO_PROD_HARMS_PROFESSIONAL_030_PLUS ZORRO_ID(HARMS_PROFESSIONAL, 0x10, 0) +#define ZORRO_PROD_HARMS_PROFESSIONAL_3500 ZORRO_ID(HARMS_PROFESSIONAL, 0xD0, 0) + +#define ZORRO_MANUF_MICRONIK 0x0A50 +#define ZORRO_PROD_MICRONIK_RCA_120 ZORRO_ID(MICRONIK, 0x0A, 0) + +#define ZORRO_MANUF_MICRONIK2 0x0F0F +#define ZORRO_PROD_MICRONIK2_Z3I ZORRO_ID(MICRONIK2, 0x01, 0) + +#define ZORRO_MANUF_MEGAMICRO 0x1000 +#define ZORRO_PROD_MEGAMICRO_SCRAM_500 ZORRO_ID(MEGAMICRO, 0x03, 0) +#define ZORRO_PROD_MEGAMICRO_SCRAM_500_RAM ZORRO_ID(MEGAMICRO, 0x04, 0) + +#define ZORRO_MANUF_IMTRONICS_2 0x1028 +#define ZORRO_PROD_IMTRONICS_HURRICANE_2800_3 ZORRO_ID(IMTRONICS_2, 0x39, 0) +#define ZORRO_PROD_IMTRONICS_HURRICANE_2800_4 ZORRO_ID(IMTRONICS_2, 0x57, 0) + +/* unofficial ID */ +#define ZORRO_MANUF_INDIVIDUAL_COMPUTERS 0x1212 +#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x00, 0) +#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x17, 0) +#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x2A, 0) + +#define ZORRO_MANUF_KUPKE_3 0x1248 +#define ZORRO_PROD_KUPKE_GOLEM_HD_3000 ZORRO_ID(KUPKE_3, 0x01, 0) + +#define ZORRO_MANUF_ITH 0x1388 +#define ZORRO_PROD_ITH_ISDN_MASTER_II ZORRO_ID(ITH, 0x01, 0) + +#define ZORRO_MANUF_VMC 0x1389 +#define ZORRO_PROD_VMC_ISDN_BLASTER_Z2 ZORRO_ID(VMC, 0x01, 0) +#define ZORRO_PROD_VMC_HYPERCOM_4 ZORRO_ID(VMC, 0x02, 0) + +#define ZORRO_MANUF_INFORMATION 0x157C +#define ZORRO_PROD_INFORMATION_ISDN_ENGINE_I ZORRO_ID(INFORMATION, 0x64, 0) + +#define ZORRO_MANUF_VORTEX 0x2017 +#define ZORRO_PROD_VORTEX_GOLDEN_GATE_80386SX ZORRO_ID(VORTEX, 0x07, 0) +#define ZORRO_PROD_VORTEX_GOLDEN_GATE_RAM ZORRO_ID(VORTEX, 0x08, 0) +#define ZORRO_PROD_VORTEX_GOLDEN_GATE_80486 ZORRO_ID(VORTEX, 0x09, 0) + +#define ZORRO_MANUF_EXPANSION_SYSTEMS 0x2062 +#define ZORRO_PROD_EXPANSION_SYSTEMS_DATAFLYER_4000SX ZORRO_ID(EXPANSION_SYSTEMS, 0x01, 0) +#define ZORRO_PROD_EXPANSION_SYSTEMS_DATAFLYER_4000SX_RAM ZORRO_ID(EXPANSION_SYSTEMS, 0x02, 0) + +#define ZORRO_MANUF_READYSOFT 0x2100 +#define ZORRO_PROD_READYSOFT_AMAX_II_IV ZORRO_ID(READYSOFT, 0x01, 0) + +#define ZORRO_MANUF_PHASE5 0x2140 +#define ZORRO_PROD_PHASE5_BLIZZARD_RAM ZORRO_ID(PHASE5, 0x01, 0) +#define ZORRO_PROD_PHASE5_BLIZZARD ZORRO_ID(PHASE5, 0x02, 0) +#define ZORRO_PROD_PHASE5_BLIZZARD_1220_IV ZORRO_ID(PHASE5, 0x06, 0) +#define ZORRO_PROD_PHASE5_FASTLANE_Z3_RAM ZORRO_ID(PHASE5, 0x0A, 0) +#define ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060 ZORRO_ID(PHASE5, 0x0B, 0) +#define ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM ZORRO_ID(PHASE5, 0x0C, 0) +#define ZORRO_PROD_PHASE5_BLIZZARD_1230 ZORRO_ID(PHASE5, 0x0D, 0) +#define ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260 ZORRO_ID(PHASE5, 0x11, 0) +#define ZORRO_PROD_PHASE5_BLIZZARD_2060 ZORRO_ID(PHASE5, 0x18, 0) +#define ZORRO_PROD_PHASE5_CYBERSTORM_MK_II ZORRO_ID(PHASE5, 0x19, 0) +#define ZORRO_PROD_PHASE5_CYBERVISION64 ZORRO_ID(PHASE5, 0x22, 0) +#define ZORRO_PROD_PHASE5_CYBERVISION64_3D_PROTOTYPE ZORRO_ID(PHASE5, 0x32, 0) +#define ZORRO_PROD_PHASE5_CYBERVISION64_3D ZORRO_ID(PHASE5, 0x43, 0) +#define ZORRO_PROD_PHASE5_CYBERSTORM_MK_III ZORRO_ID(PHASE5, 0x64, 0) +#define ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS ZORRO_ID(PHASE5, 0x6e, 0) + +#define ZORRO_MANUF_DPS 0x2169 +#define ZORRO_PROD_DPS_PERSONAL_ANIMATION_RECORDER ZORRO_ID(DPS, 0x01, 0) + +#define ZORRO_MANUF_APOLLO_2 0x2200 +#define ZORRO_PROD_APOLLO_A620_68020_1 ZORRO_ID(APOLLO_2, 0x00, 0) +#define ZORRO_PROD_APOLLO_A620_68020_2 ZORRO_ID(APOLLO_2, 0x01, 0) + +#define ZORRO_MANUF_APOLLO_3 0x2222 +#define ZORRO_PROD_APOLLO_AT_APOLLO ZORRO_ID(APOLLO_3, 0x22, 0) +#define ZORRO_PROD_APOLLO_1230_1240_1260_2030_4040_4060 ZORRO_ID(APOLLO_3, 0x23, 0) + +#define ZORRO_MANUF_PETSOFF_LP 0x38A5 +#define ZORRO_PROD_PETSOFF_LP_DELFINA ZORRO_ID(PETSOFF_LP, 0x00, 0) +#define ZORRO_PROD_PETSOFF_LP_DELFINA_LITE ZORRO_ID(PETSOFF_LP, 0x01, 0) + +#define ZORRO_MANUF_UWE_GERLACH 0x3FF7 +#define ZORRO_PROD_UWE_GERLACH_RAM_ROM ZORRO_ID(UWE_GERLACH, 0xd4, 0) + +#define ZORRO_MANUF_ACT 0x4231 +#define ZORRO_PROD_ACT_PRELUDE ZORRO_ID(ACT, 0x01, 0) + +#define ZORRO_MANUF_MACROSYSTEMS_GERMANY 0x4754 +#define ZORRO_PROD_MACROSYSTEMS_MAESTRO ZORRO_ID(MACROSYSTEMS_GERMANY, 0x03, 0) +#define ZORRO_PROD_MACROSYSTEMS_VLAB ZORRO_ID(MACROSYSTEMS_GERMANY, 0x04, 0) +#define ZORRO_PROD_MACROSYSTEMS_MAESTRO_PRO ZORRO_ID(MACROSYSTEMS_GERMANY, 0x05, 0) +#define ZORRO_PROD_MACROSYSTEMS_RETINA ZORRO_ID(MACROSYSTEMS_GERMANY, 0x06, 0) +#define ZORRO_PROD_MACROSYSTEMS_MULTI_EVOLUTION ZORRO_ID(MACROSYSTEMS_GERMANY, 0x08, 0) +#define ZORRO_PROD_MACROSYSTEMS_TOCCATA ZORRO_ID(MACROSYSTEMS_GERMANY, 0x0C, 0) +#define ZORRO_PROD_MACROSYSTEMS_RETINA_Z3 ZORRO_ID(MACROSYSTEMS_GERMANY, 0x10, 0) +#define ZORRO_PROD_MACROSYSTEMS_VLAB_MOTION ZORRO_ID(MACROSYSTEMS_GERMANY, 0x12, 0) +#define ZORRO_PROD_MACROSYSTEMS_ALTAIS ZORRO_ID(MACROSYSTEMS_GERMANY, 0x13, 0) +#define ZORRO_PROD_MACROSYSTEMS_FALCON_040 ZORRO_ID(MACROSYSTEMS_GERMANY, 0xFD, 0) + +#define ZORRO_MANUF_COMBITEC 0x6766 + +#define ZORRO_MANUF_SKI_PERIPHERALS 0x8000 +#define ZORRO_PROD_SKI_PERIPHERALS_MAST_FIREBALL ZORRO_ID(SKI_PERIPHERALS, 0x08, 0) +#define ZORRO_PROD_SKI_PERIPHERALS_SCSI_DUAL_SERIAL ZORRO_ID(SKI_PERIPHERALS, 0x80, 0) + +#define ZORRO_MANUF_REIS_WARE_2 0xA9AD +#define ZORRO_PROD_REIS_WARE_SCAN_KING ZORRO_ID(REIS_WARE_2, 0x11, 0) + +#define ZORRO_MANUF_CAMERON 0xAA01 +#define ZORRO_PROD_CAMERON_PERSONAL_A4 ZORRO_ID(CAMERON, 0x10, 0) + +#define ZORRO_MANUF_REIS_WARE 0xAA11 +#define ZORRO_PROD_REIS_WARE_HANDYSCANNER ZORRO_ID(REIS_WARE, 0x11, 0) + +#define ZORRO_MANUF_PHOENIX_2 0xB5A8 +#define ZORRO_PROD_PHOENIX_ST506_2 ZORRO_ID(PHOENIX_2, 0x21, 0) +#define ZORRO_PROD_PHOENIX_SCSI_2 ZORRO_ID(PHOENIX_2, 0x22, 0) +#define ZORRO_PROD_PHOENIX_RAM_2 ZORRO_ID(PHOENIX_2, 0xBE, 0) + +#define ZORRO_MANUF_COMBITEC_2 0xC008 +#define ZORRO_PROD_COMBITEC_HD ZORRO_ID(COMBITEC_2, 0x2A, 0) +#define ZORRO_PROD_COMBITEC_SRAM ZORRO_ID(COMBITEC_2, 0x2B, 0) + + + /* + * Test and illegal Manufacturer IDs. + */ + +#define ZORRO_MANUF_HACKER 0x07DB +#define ZORRO_PROD_GENERAL_PROTOTYPE ZORRO_ID(HACKER, 0x00, 0) +#define ZORRO_PROD_HACKER_SCSI ZORRO_ID(HACKER, 0x01, 0) +#define ZORRO_PROD_RESOURCE_MANAGEMENT_FORCE_QUICKNET_QN2000 ZORRO_ID(HACKER, 0x02, 0) +#define ZORRO_PROD_VECTOR_CONNECTION_2 ZORRO_ID(HACKER, 0xE0, 0) +#define ZORRO_PROD_VECTOR_CONNECTION_3 ZORRO_ID(HACKER, 0xE1, 0) +#define ZORRO_PROD_VECTOR_CONNECTION_4 ZORRO_ID(HACKER, 0xE2, 0) +#define ZORRO_PROD_VECTOR_CONNECTION_5 ZORRO_ID(HACKER, 0xE3, 0) -- cgit v1.2.3-59-g8ed1b From 5800dc3cff87c3a1548382298bb16e1fb4ec7e32 Mon Sep 17 00:00:00 2001 From: Jason Baron Date: Mon, 25 Nov 2013 23:23:04 +0000 Subject: panic: Make panic_timeout configurable The panic_timeout value can be set via the command line option 'panic=x', or via /proc/sys/kernel/panic, however that is not sufficient when the panic occurs before we are able to set up these values. Thus, add a CONFIG_PANIC_TIMEOUT so that we can set the desired value from the .config. The default panic_timeout value continues to be 0 - wait forever. Also adds set_arch_panic_timeout(new_timeout, arch_default_timeout), which is intended to be used by arches in arch_setup(). The idea being that the new_timeout is only set if the user hasn't changed from the arch_default_timeout. Signed-off-by: Jason Baron Cc: benh@kernel.crashing.org Cc: paulus@samba.org Cc: ralf@linux-mips.org Cc: mpe@ellerman.id.au Cc: felipe.contreras@gmail.com Cc: Linus Torvalds Cc: Andrew Morton Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1a1674daec27c534df409697025ac568ebcee91e.1385418410.git.jbaron@akamai.com Signed-off-by: Ingo Molnar --- include/linux/kernel.h | 9 +++++++++ kernel/panic.c | 2 +- lib/Kconfig.debug | 9 +++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index d4e98d13eff4..2ac02772a86e 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -393,6 +393,15 @@ extern int panic_on_oops; extern int panic_on_unrecovered_nmi; extern int panic_on_io_nmi; extern int sysctl_panic_on_stackoverflow; +/* + * Only to be used by arch init code. If the user over-wrote the default + * CONFIG_PANIC_TIMEOUT, honor it. + */ +static inline void set_arch_panic_timeout(int timeout, int arch_default_timeout) +{ + if (panic_timeout == arch_default_timeout) + panic_timeout = timeout; +} extern const char *print_tainted(void); enum lockdep_ok { LOCKDEP_STILL_OK, diff --git a/kernel/panic.c b/kernel/panic.c index c00b4ceb39e8..6d6300375090 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -33,7 +33,7 @@ static int pause_on_oops; static int pause_on_oops_flag; static DEFINE_SPINLOCK(pause_on_oops_lock); -int panic_timeout; +int panic_timeout = CONFIG_PANIC_TIMEOUT; EXPORT_SYMBOL_GPL(panic_timeout); ATOMIC_NOTIFIER_HEAD(panic_notifier_list); diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index db25707aa41b..6982094a7e74 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -761,6 +761,15 @@ config PANIC_ON_OOPS_VALUE default 0 if !PANIC_ON_OOPS default 1 if PANIC_ON_OOPS +config PANIC_TIMEOUT + int "panic timeout" + default 0 + help + Set the timeout value (in seconds) until a reboot occurs when the + the kernel panics. If n = 0, then we wait forever. A timeout + value n > 0 will wait n seconds before rebooting, while a timeout + value n < 0 will reboot immediately. + config SCHED_DEBUG bool "Collect scheduler debugging info" depends on DEBUG_KERNEL && PROC_FS -- cgit v1.2.3-59-g8ed1b From 869c597829817af4b9f85c5e4181c622918dc781 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 26 Nov 2013 13:31:14 +0100 Subject: usb: musb: dsps: add support for suspend and resume The dsps platform needs to save save some registers at suspend time and restore them after resume. This patch adds a struct for these registers, and also lets the musb core know that the core registers need to be saved as well. We also have to explicitly de-assert the port reset upon resume on this platform, but musb_port_reset() should not be called from glue layers. Hence, introduce a flag in struct musb_hdrc_config for this. Signed-off-by: Daniel Mack Signed-off-by: Felipe Balbi --- drivers/usb/musb/musb_dsps.c | 57 +++++++++++++++++++++++++++++++++++++++++ drivers/usb/musb/musb_host.c | 7 ++++- drivers/usb/musb/musb_host.h | 2 ++ drivers/usb/musb/musb_virthub.c | 2 +- include/linux/usb/musb.h | 3 +++ 5 files changed, 69 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 3f3724471667..7cfa6e80ad60 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -113,6 +113,19 @@ struct dsps_musb_wrapper { u8 poll_seconds; }; +/* + * register shadow for suspend + */ +struct dsps_context { + u32 control; + u32 epintr; + u32 coreintr; + u32 phy_utmi; + u32 mode; + u32 tx_mode; + u32 rx_mode; +}; + /** * DSPS glue structure. */ @@ -122,6 +135,8 @@ struct dsps_glue { const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ struct timer_list timer; /* otg_workaround timer */ unsigned long last_timer; /* last timer data for each instance */ + + struct dsps_context context; }; static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) @@ -559,6 +574,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, config->num_eps = get_int_prop(dn, "mentor,num-eps"); config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); + config->host_port_deassert_reset_at_resume = 1; pdata.mode = get_musb_port_mode(dev); /* DT keeps this entry in mA, musb expects it as per USB spec */ pdata.power = get_int_prop(dn, "mentor,power") / 2; @@ -683,11 +699,52 @@ static const struct of_device_id musb_dsps_of_match[] = { }; MODULE_DEVICE_TABLE(of, musb_dsps_of_match); +#ifdef CONFIG_PM +static int dsps_suspend(struct device *dev) +{ + struct dsps_glue *glue = dev_get_drvdata(dev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + struct musb *musb = platform_get_drvdata(glue->musb); + void __iomem *mbase = musb->ctrl_base; + + glue->context.control = dsps_readl(mbase, wrp->control); + glue->context.epintr = dsps_readl(mbase, wrp->epintr_set); + glue->context.coreintr = dsps_readl(mbase, wrp->coreintr_set); + glue->context.phy_utmi = dsps_readl(mbase, wrp->phy_utmi); + glue->context.mode = dsps_readl(mbase, wrp->mode); + glue->context.tx_mode = dsps_readl(mbase, wrp->tx_mode); + glue->context.rx_mode = dsps_readl(mbase, wrp->rx_mode); + + return 0; +} + +static int dsps_resume(struct device *dev) +{ + struct dsps_glue *glue = dev_get_drvdata(dev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + struct musb *musb = platform_get_drvdata(glue->musb); + void __iomem *mbase = musb->ctrl_base; + + dsps_writel(mbase, wrp->control, glue->context.control); + dsps_writel(mbase, wrp->epintr_set, glue->context.epintr); + dsps_writel(mbase, wrp->coreintr_set, glue->context.coreintr); + dsps_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi); + dsps_writel(mbase, wrp->mode, glue->context.mode); + dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode); + dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); + static struct platform_driver dsps_usbss_driver = { .probe = dsps_probe, .remove = dsps_remove, .driver = { .name = "musb-dsps", + .pm = &dsps_pm_ops, .of_match_table = musb_dsps_of_match, }, }; diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 81caf9f4eb1a..822413899260 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2464,7 +2464,12 @@ static int musb_bus_suspend(struct usb_hcd *hcd) static int musb_bus_resume(struct usb_hcd *hcd) { - /* resuming child port does the work */ + struct musb *musb = hcd_to_musb(hcd); + + if (musb->config && + musb->config->host_port_deassert_reset_at_resume) + musb_port_reset(musb, false); + return 0; } diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index e660af90272d..7436c24af0ff 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -93,6 +93,7 @@ extern void musb_root_disconnect(struct musb *musb); extern void musb_host_resume_root_hub(struct musb *musb); extern void musb_host_poke_root_hub(struct musb *musb); extern void musb_port_suspend(struct musb *musb, bool do_suspend); +extern void musb_port_reset(struct musb *musb, bool do_reset); #else static inline struct musb *hcd_to_musb(struct usb_hcd *hcd) { @@ -123,6 +124,7 @@ static inline void musb_host_resume_root_hub(struct musb *musb) {} static inline void musb_host_poll_rh_status(struct musb *musb) {} static inline void musb_host_poke_root_hub(struct musb *musb) {} static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {} +static inline void musb_port_reset(struct musb *musb) {} #endif struct usb_hcd; diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index e977441401ed..24e46c0c84b5 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -109,7 +109,7 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) } } -static void musb_port_reset(struct musb *musb, bool do_reset) +void musb_port_reset(struct musb *musb, bool do_reset) { u8 power; void __iomem *mbase = musb->mregs; diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h index eb505250940a..a4ee1b582183 100644 --- a/include/linux/usb/musb.h +++ b/include/linux/usb/musb.h @@ -76,6 +76,9 @@ struct musb_hdrc_config { unsigned dma:1 __deprecated; /* supports DMA */ unsigned vendor_req:1 __deprecated; /* vendor registers required */ + /* need to explicitly de-assert the port reset after resume? */ + unsigned host_port_deassert_reset_at_resume:1; + u8 num_eps; /* number of endpoints _with_ ep0 */ u8 dma_channels __deprecated; /* number of dma channels */ u8 dyn_fifo_size; /* dynamic size in bytes */ -- cgit v1.2.3-59-g8ed1b From 5653668c9585441926dd2575791f6b5bb84bb254 Mon Sep 17 00:00:00 2001 From: Anton Tikhomirov Date: Tue, 26 Nov 2013 11:47:02 +0900 Subject: usb: phy: move OTG FSM header Other USB drivers may want to use OTG final state machine implementation, so make this header available for them. Signed-off-by: Anton Tikhomirov Signed-off-by: Felipe Balbi --- drivers/usb/phy/phy-fsl-usb.h | 2 +- drivers/usb/phy/phy-fsm-usb.c | 3 +- drivers/usb/phy/phy-fsm-usb.h | 244 ------------------------------------------ include/linux/usb/otg-fsm.h | 244 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 246 insertions(+), 247 deletions(-) delete mode 100644 drivers/usb/phy/phy-fsm-usb.h create mode 100644 include/linux/usb/otg-fsm.h (limited to 'include/linux') diff --git a/drivers/usb/phy/phy-fsl-usb.h b/drivers/usb/phy/phy-fsl-usb.h index 7365170a2f23..5986c96354df 100644 --- a/drivers/usb/phy/phy-fsl-usb.h +++ b/drivers/usb/phy/phy-fsl-usb.h @@ -15,7 +15,7 @@ * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include "phy-fsm-usb.h" +#include #include #include diff --git a/drivers/usb/phy/phy-fsm-usb.c b/drivers/usb/phy/phy-fsm-usb.c index 2817b04a6c47..62238726fb1c 100644 --- a/drivers/usb/phy/phy-fsm-usb.c +++ b/drivers/usb/phy/phy-fsm-usb.c @@ -28,8 +28,7 @@ #include #include #include - -#include "phy-fsm-usb.h" +#include /* Change USB protocol when there is a protocol change */ static int otg_set_protocol(struct otg_fsm *fsm, int protocol) diff --git a/drivers/usb/phy/phy-fsm-usb.h b/drivers/usb/phy/phy-fsm-usb.h deleted file mode 100644 index b6ba1bfb86f2..000000000000 --- a/drivers/usb/phy/phy-fsm-usb.h +++ /dev/null @@ -1,244 +0,0 @@ -/* Copyright (C) 2007,2008 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __LINUX_USB_OTG_FSM_H -#define __LINUX_USB_OTG_FSM_H - -#include -#include - -#undef VERBOSE - -#ifdef VERBOSE -#define VDBG(fmt, args...) pr_debug("[%s] " fmt , \ - __func__, ## args) -#else -#define VDBG(stuff...) do {} while (0) -#endif - -#ifdef VERBOSE -#define MPC_LOC printk("Current Location [%s]:[%d]\n", __FILE__, __LINE__) -#else -#define MPC_LOC do {} while (0) -#endif - -#define PROTO_UNDEF (0) -#define PROTO_HOST (1) -#define PROTO_GADGET (2) - -enum otg_fsm_timer { - /* Standard OTG timers */ - A_WAIT_VRISE, - A_WAIT_VFALL, - A_WAIT_BCON, - A_AIDL_BDIS, - B_ASE0_BRST, - A_BIDL_ADIS, - - /* Auxiliary timers */ - B_SE0_SRP, - B_SRP_FAIL, - A_WAIT_ENUM, - - NUM_OTG_FSM_TIMERS, -}; - -/* OTG state machine according to the OTG spec */ -struct otg_fsm { - /* Input */ - int id; - int adp_change; - int power_up; - int test_device; - int a_bus_drop; - int a_bus_req; - int a_srp_det; - int a_vbus_vld; - int b_conn; - int a_bus_resume; - int a_bus_suspend; - int a_conn; - int b_bus_req; - int b_se0_srp; - int b_ssend_srp; - int b_sess_vld; - /* Auxilary inputs */ - int a_sess_vld; - int b_bus_resume; - int b_bus_suspend; - - /* Output */ - int data_pulse; - int drv_vbus; - int loc_conn; - int loc_sof; - int adp_prb; - int adp_sns; - - /* Internal variables */ - int a_set_b_hnp_en; - int b_srp_done; - int b_hnp_enable; - int a_clr_err; - - /* Informative variables */ - int a_bus_drop_inf; - int a_bus_req_inf; - int a_clr_err_inf; - int b_bus_req_inf; - /* Auxilary informative variables */ - int a_suspend_req_inf; - - /* Timeout indicator for timers */ - int a_wait_vrise_tmout; - int a_wait_vfall_tmout; - int a_wait_bcon_tmout; - int a_aidl_bdis_tmout; - int b_ase0_brst_tmout; - int a_bidl_adis_tmout; - - struct otg_fsm_ops *ops; - struct usb_otg *otg; - - /* Current usb protocol used: 0:undefine; 1:host; 2:client */ - int protocol; - struct mutex lock; -}; - -struct otg_fsm_ops { - void (*chrg_vbus)(struct otg_fsm *fsm, int on); - void (*drv_vbus)(struct otg_fsm *fsm, int on); - void (*loc_conn)(struct otg_fsm *fsm, int on); - void (*loc_sof)(struct otg_fsm *fsm, int on); - void (*start_pulse)(struct otg_fsm *fsm); - void (*start_adp_prb)(struct otg_fsm *fsm); - void (*start_adp_sns)(struct otg_fsm *fsm); - void (*add_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer); - void (*del_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer); - int (*start_host)(struct otg_fsm *fsm, int on); - int (*start_gadget)(struct otg_fsm *fsm, int on); -}; - - -static inline int otg_chrg_vbus(struct otg_fsm *fsm, int on) -{ - if (!fsm->ops->chrg_vbus) - return -EOPNOTSUPP; - fsm->ops->chrg_vbus(fsm, on); - return 0; -} - -static inline int otg_drv_vbus(struct otg_fsm *fsm, int on) -{ - if (!fsm->ops->drv_vbus) - return -EOPNOTSUPP; - if (fsm->drv_vbus != on) { - fsm->drv_vbus = on; - fsm->ops->drv_vbus(fsm, on); - } - return 0; -} - -static inline int otg_loc_conn(struct otg_fsm *fsm, int on) -{ - if (!fsm->ops->loc_conn) - return -EOPNOTSUPP; - if (fsm->loc_conn != on) { - fsm->loc_conn = on; - fsm->ops->loc_conn(fsm, on); - } - return 0; -} - -static inline int otg_loc_sof(struct otg_fsm *fsm, int on) -{ - if (!fsm->ops->loc_sof) - return -EOPNOTSUPP; - if (fsm->loc_sof != on) { - fsm->loc_sof = on; - fsm->ops->loc_sof(fsm, on); - } - return 0; -} - -static inline int otg_start_pulse(struct otg_fsm *fsm) -{ - if (!fsm->ops->start_pulse) - return -EOPNOTSUPP; - if (!fsm->data_pulse) { - fsm->data_pulse = 1; - fsm->ops->start_pulse(fsm); - } - return 0; -} - -static inline int otg_start_adp_prb(struct otg_fsm *fsm) -{ - if (!fsm->ops->start_adp_prb) - return -EOPNOTSUPP; - if (!fsm->adp_prb) { - fsm->adp_sns = 0; - fsm->adp_prb = 1; - fsm->ops->start_adp_prb(fsm); - } - return 0; -} - -static inline int otg_start_adp_sns(struct otg_fsm *fsm) -{ - if (!fsm->ops->start_adp_sns) - return -EOPNOTSUPP; - if (!fsm->adp_sns) { - fsm->adp_sns = 1; - fsm->ops->start_adp_sns(fsm); - } - return 0; -} - -static inline int otg_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer) -{ - if (!fsm->ops->add_timer) - return -EOPNOTSUPP; - fsm->ops->add_timer(fsm, timer); - return 0; -} - -static inline int otg_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer) -{ - if (!fsm->ops->del_timer) - return -EOPNOTSUPP; - fsm->ops->del_timer(fsm, timer); - return 0; -} - -static inline int otg_start_host(struct otg_fsm *fsm, int on) -{ - if (!fsm->ops->start_host) - return -EOPNOTSUPP; - return fsm->ops->start_host(fsm, on); -} - -static inline int otg_start_gadget(struct otg_fsm *fsm, int on) -{ - if (!fsm->ops->start_gadget) - return -EOPNOTSUPP; - return fsm->ops->start_gadget(fsm, on); -} - -int otg_statemachine(struct otg_fsm *fsm); - -#endif /* __LINUX_USB_OTG_FSM_H */ diff --git a/include/linux/usb/otg-fsm.h b/include/linux/usb/otg-fsm.h new file mode 100644 index 000000000000..b6ba1bfb86f2 --- /dev/null +++ b/include/linux/usb/otg-fsm.h @@ -0,0 +1,244 @@ +/* Copyright (C) 2007,2008 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __LINUX_USB_OTG_FSM_H +#define __LINUX_USB_OTG_FSM_H + +#include +#include + +#undef VERBOSE + +#ifdef VERBOSE +#define VDBG(fmt, args...) pr_debug("[%s] " fmt , \ + __func__, ## args) +#else +#define VDBG(stuff...) do {} while (0) +#endif + +#ifdef VERBOSE +#define MPC_LOC printk("Current Location [%s]:[%d]\n", __FILE__, __LINE__) +#else +#define MPC_LOC do {} while (0) +#endif + +#define PROTO_UNDEF (0) +#define PROTO_HOST (1) +#define PROTO_GADGET (2) + +enum otg_fsm_timer { + /* Standard OTG timers */ + A_WAIT_VRISE, + A_WAIT_VFALL, + A_WAIT_BCON, + A_AIDL_BDIS, + B_ASE0_BRST, + A_BIDL_ADIS, + + /* Auxiliary timers */ + B_SE0_SRP, + B_SRP_FAIL, + A_WAIT_ENUM, + + NUM_OTG_FSM_TIMERS, +}; + +/* OTG state machine according to the OTG spec */ +struct otg_fsm { + /* Input */ + int id; + int adp_change; + int power_up; + int test_device; + int a_bus_drop; + int a_bus_req; + int a_srp_det; + int a_vbus_vld; + int b_conn; + int a_bus_resume; + int a_bus_suspend; + int a_conn; + int b_bus_req; + int b_se0_srp; + int b_ssend_srp; + int b_sess_vld; + /* Auxilary inputs */ + int a_sess_vld; + int b_bus_resume; + int b_bus_suspend; + + /* Output */ + int data_pulse; + int drv_vbus; + int loc_conn; + int loc_sof; + int adp_prb; + int adp_sns; + + /* Internal variables */ + int a_set_b_hnp_en; + int b_srp_done; + int b_hnp_enable; + int a_clr_err; + + /* Informative variables */ + int a_bus_drop_inf; + int a_bus_req_inf; + int a_clr_err_inf; + int b_bus_req_inf; + /* Auxilary informative variables */ + int a_suspend_req_inf; + + /* Timeout indicator for timers */ + int a_wait_vrise_tmout; + int a_wait_vfall_tmout; + int a_wait_bcon_tmout; + int a_aidl_bdis_tmout; + int b_ase0_brst_tmout; + int a_bidl_adis_tmout; + + struct otg_fsm_ops *ops; + struct usb_otg *otg; + + /* Current usb protocol used: 0:undefine; 1:host; 2:client */ + int protocol; + struct mutex lock; +}; + +struct otg_fsm_ops { + void (*chrg_vbus)(struct otg_fsm *fsm, int on); + void (*drv_vbus)(struct otg_fsm *fsm, int on); + void (*loc_conn)(struct otg_fsm *fsm, int on); + void (*loc_sof)(struct otg_fsm *fsm, int on); + void (*start_pulse)(struct otg_fsm *fsm); + void (*start_adp_prb)(struct otg_fsm *fsm); + void (*start_adp_sns)(struct otg_fsm *fsm); + void (*add_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer); + void (*del_timer)(struct otg_fsm *fsm, enum otg_fsm_timer timer); + int (*start_host)(struct otg_fsm *fsm, int on); + int (*start_gadget)(struct otg_fsm *fsm, int on); +}; + + +static inline int otg_chrg_vbus(struct otg_fsm *fsm, int on) +{ + if (!fsm->ops->chrg_vbus) + return -EOPNOTSUPP; + fsm->ops->chrg_vbus(fsm, on); + return 0; +} + +static inline int otg_drv_vbus(struct otg_fsm *fsm, int on) +{ + if (!fsm->ops->drv_vbus) + return -EOPNOTSUPP; + if (fsm->drv_vbus != on) { + fsm->drv_vbus = on; + fsm->ops->drv_vbus(fsm, on); + } + return 0; +} + +static inline int otg_loc_conn(struct otg_fsm *fsm, int on) +{ + if (!fsm->ops->loc_conn) + return -EOPNOTSUPP; + if (fsm->loc_conn != on) { + fsm->loc_conn = on; + fsm->ops->loc_conn(fsm, on); + } + return 0; +} + +static inline int otg_loc_sof(struct otg_fsm *fsm, int on) +{ + if (!fsm->ops->loc_sof) + return -EOPNOTSUPP; + if (fsm->loc_sof != on) { + fsm->loc_sof = on; + fsm->ops->loc_sof(fsm, on); + } + return 0; +} + +static inline int otg_start_pulse(struct otg_fsm *fsm) +{ + if (!fsm->ops->start_pulse) + return -EOPNOTSUPP; + if (!fsm->data_pulse) { + fsm->data_pulse = 1; + fsm->ops->start_pulse(fsm); + } + return 0; +} + +static inline int otg_start_adp_prb(struct otg_fsm *fsm) +{ + if (!fsm->ops->start_adp_prb) + return -EOPNOTSUPP; + if (!fsm->adp_prb) { + fsm->adp_sns = 0; + fsm->adp_prb = 1; + fsm->ops->start_adp_prb(fsm); + } + return 0; +} + +static inline int otg_start_adp_sns(struct otg_fsm *fsm) +{ + if (!fsm->ops->start_adp_sns) + return -EOPNOTSUPP; + if (!fsm->adp_sns) { + fsm->adp_sns = 1; + fsm->ops->start_adp_sns(fsm); + } + return 0; +} + +static inline int otg_add_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer) +{ + if (!fsm->ops->add_timer) + return -EOPNOTSUPP; + fsm->ops->add_timer(fsm, timer); + return 0; +} + +static inline int otg_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer timer) +{ + if (!fsm->ops->del_timer) + return -EOPNOTSUPP; + fsm->ops->del_timer(fsm, timer); + return 0; +} + +static inline int otg_start_host(struct otg_fsm *fsm, int on) +{ + if (!fsm->ops->start_host) + return -EOPNOTSUPP; + return fsm->ops->start_host(fsm, on); +} + +static inline int otg_start_gadget(struct otg_fsm *fsm, int on) +{ + if (!fsm->ops->start_gadget) + return -EOPNOTSUPP; + return fsm->ops->start_gadget(fsm, on); +} + +int otg_statemachine(struct otg_fsm *fsm); + +#endif /* __LINUX_USB_OTG_FSM_H */ -- cgit v1.2.3-59-g8ed1b From 8d99339710ac9bd1eca8f04a356752c89dc7cf0b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 19 Nov 2013 23:02:11 +0100 Subject: pinctrl: nomadik: move platform data handling into driver This decomissions the platform data header (which is no longer in use after the systems using this driver were switched to a pure device-tree config path) and merges the result into the driver file or local driver header. Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-nomadik.c | 216 ++++++++++++++++++++++- drivers/pinctrl/pinctrl-nomadik.h | 14 +- include/linux/platform_data/pinctrl-nomadik.h | 242 -------------------------- 3 files changed, 227 insertions(+), 245 deletions(-) delete mode 100644 include/linux/platform_data/pinctrl-nomadik.h (limited to 'include/linux') diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 7111c3b59130..3895f1415ef9 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -33,7 +33,6 @@ #include /* Since we request GPIOs from ourself */ #include -#include #include "pinctrl-nomadik.h" #include "core.h" @@ -45,6 +44,221 @@ * Symbols in this file are called "nmk_gpio" for "nomadik gpio" */ +/* + * pin configurations are represented by 32-bit integers: + * + * bit 0.. 8 - Pin Number (512 Pins Maximum) + * bit 9..10 - Alternate Function Selection + * bit 11..12 - Pull up/down state + * bit 13 - Sleep mode behaviour + * bit 14 - Direction + * bit 15 - Value (if output) + * bit 16..18 - SLPM pull up/down state + * bit 19..20 - SLPM direction + * bit 21..22 - SLPM Value (if output) + * bit 23..25 - PDIS value (if input) + * bit 26 - Gpio mode + * bit 27 - Sleep mode + * + * to facilitate the definition, the following macros are provided + * + * PIN_CFG_DEFAULT - default config (0): + * pull up/down = disabled + * sleep mode = input/wakeup + * direction = input + * value = low + * SLPM direction = same as normal + * SLPM pull = same as normal + * SLPM value = same as normal + * + * PIN_CFG - default config with alternate function + */ + +typedef unsigned long pin_cfg_t; + +#define PIN_NUM_MASK 0x1ff +#define PIN_NUM(x) ((x) & PIN_NUM_MASK) + +#define PIN_ALT_SHIFT 9 +#define PIN_ALT_MASK (0x3 << PIN_ALT_SHIFT) +#define PIN_ALT(x) (((x) & PIN_ALT_MASK) >> PIN_ALT_SHIFT) +#define PIN_GPIO (NMK_GPIO_ALT_GPIO << PIN_ALT_SHIFT) +#define PIN_ALT_A (NMK_GPIO_ALT_A << PIN_ALT_SHIFT) +#define PIN_ALT_B (NMK_GPIO_ALT_B << PIN_ALT_SHIFT) +#define PIN_ALT_C (NMK_GPIO_ALT_C << PIN_ALT_SHIFT) + +#define PIN_PULL_SHIFT 11 +#define PIN_PULL_MASK (0x3 << PIN_PULL_SHIFT) +#define PIN_PULL(x) (((x) & PIN_PULL_MASK) >> PIN_PULL_SHIFT) +#define PIN_PULL_NONE (NMK_GPIO_PULL_NONE << PIN_PULL_SHIFT) +#define PIN_PULL_UP (NMK_GPIO_PULL_UP << PIN_PULL_SHIFT) +#define PIN_PULL_DOWN (NMK_GPIO_PULL_DOWN << PIN_PULL_SHIFT) + +#define PIN_SLPM_SHIFT 13 +#define PIN_SLPM_MASK (0x1 << PIN_SLPM_SHIFT) +#define PIN_SLPM(x) (((x) & PIN_SLPM_MASK) >> PIN_SLPM_SHIFT) +#define PIN_SLPM_MAKE_INPUT (NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT) +#define PIN_SLPM_NOCHANGE (NMK_GPIO_SLPM_NOCHANGE << PIN_SLPM_SHIFT) +/* These two replace the above in DB8500v2+ */ +#define PIN_SLPM_WAKEUP_ENABLE (NMK_GPIO_SLPM_WAKEUP_ENABLE << PIN_SLPM_SHIFT) +#define PIN_SLPM_WAKEUP_DISABLE (NMK_GPIO_SLPM_WAKEUP_DISABLE << PIN_SLPM_SHIFT) +#define PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP PIN_SLPM_WAKEUP_DISABLE + +#define PIN_SLPM_GPIO PIN_SLPM_WAKEUP_ENABLE /* In SLPM, pin is a gpio */ +#define PIN_SLPM_ALTFUNC PIN_SLPM_WAKEUP_DISABLE /* In SLPM, pin is altfunc */ + +#define PIN_DIR_SHIFT 14 +#define PIN_DIR_MASK (0x1 << PIN_DIR_SHIFT) +#define PIN_DIR(x) (((x) & PIN_DIR_MASK) >> PIN_DIR_SHIFT) +#define PIN_DIR_INPUT (0 << PIN_DIR_SHIFT) +#define PIN_DIR_OUTPUT (1 << PIN_DIR_SHIFT) + +#define PIN_VAL_SHIFT 15 +#define PIN_VAL_MASK (0x1 << PIN_VAL_SHIFT) +#define PIN_VAL(x) (((x) & PIN_VAL_MASK) >> PIN_VAL_SHIFT) +#define PIN_VAL_LOW (0 << PIN_VAL_SHIFT) +#define PIN_VAL_HIGH (1 << PIN_VAL_SHIFT) + +#define PIN_SLPM_PULL_SHIFT 16 +#define PIN_SLPM_PULL_MASK (0x7 << PIN_SLPM_PULL_SHIFT) +#define PIN_SLPM_PULL(x) \ + (((x) & PIN_SLPM_PULL_MASK) >> PIN_SLPM_PULL_SHIFT) +#define PIN_SLPM_PULL_NONE \ + ((1 + NMK_GPIO_PULL_NONE) << PIN_SLPM_PULL_SHIFT) +#define PIN_SLPM_PULL_UP \ + ((1 + NMK_GPIO_PULL_UP) << PIN_SLPM_PULL_SHIFT) +#define PIN_SLPM_PULL_DOWN \ + ((1 + NMK_GPIO_PULL_DOWN) << PIN_SLPM_PULL_SHIFT) + +#define PIN_SLPM_DIR_SHIFT 19 +#define PIN_SLPM_DIR_MASK (0x3 << PIN_SLPM_DIR_SHIFT) +#define PIN_SLPM_DIR(x) \ + (((x) & PIN_SLPM_DIR_MASK) >> PIN_SLPM_DIR_SHIFT) +#define PIN_SLPM_DIR_INPUT ((1 + 0) << PIN_SLPM_DIR_SHIFT) +#define PIN_SLPM_DIR_OUTPUT ((1 + 1) << PIN_SLPM_DIR_SHIFT) + +#define PIN_SLPM_VAL_SHIFT 21 +#define PIN_SLPM_VAL_MASK (0x3 << PIN_SLPM_VAL_SHIFT) +#define PIN_SLPM_VAL(x) \ + (((x) & PIN_SLPM_VAL_MASK) >> PIN_SLPM_VAL_SHIFT) +#define PIN_SLPM_VAL_LOW ((1 + 0) << PIN_SLPM_VAL_SHIFT) +#define PIN_SLPM_VAL_HIGH ((1 + 1) << PIN_SLPM_VAL_SHIFT) + +#define PIN_SLPM_PDIS_SHIFT 23 +#define PIN_SLPM_PDIS_MASK (0x3 << PIN_SLPM_PDIS_SHIFT) +#define PIN_SLPM_PDIS(x) \ + (((x) & PIN_SLPM_PDIS_MASK) >> PIN_SLPM_PDIS_SHIFT) +#define PIN_SLPM_PDIS_NO_CHANGE (0 << PIN_SLPM_PDIS_SHIFT) +#define PIN_SLPM_PDIS_DISABLED (1 << PIN_SLPM_PDIS_SHIFT) +#define PIN_SLPM_PDIS_ENABLED (2 << PIN_SLPM_PDIS_SHIFT) + +#define PIN_LOWEMI_SHIFT 25 +#define PIN_LOWEMI_MASK (0x1 << PIN_LOWEMI_SHIFT) +#define PIN_LOWEMI(x) (((x) & PIN_LOWEMI_MASK) >> PIN_LOWEMI_SHIFT) +#define PIN_LOWEMI_DISABLED (0 << PIN_LOWEMI_SHIFT) +#define PIN_LOWEMI_ENABLED (1 << PIN_LOWEMI_SHIFT) + +#define PIN_GPIOMODE_SHIFT 26 +#define PIN_GPIOMODE_MASK (0x1 << PIN_GPIOMODE_SHIFT) +#define PIN_GPIOMODE(x) (((x) & PIN_GPIOMODE_MASK) >> PIN_GPIOMODE_SHIFT) +#define PIN_GPIOMODE_DISABLED (0 << PIN_GPIOMODE_SHIFT) +#define PIN_GPIOMODE_ENABLED (1 << PIN_GPIOMODE_SHIFT) + +#define PIN_SLEEPMODE_SHIFT 27 +#define PIN_SLEEPMODE_MASK (0x1 << PIN_SLEEPMODE_SHIFT) +#define PIN_SLEEPMODE(x) (((x) & PIN_SLEEPMODE_MASK) >> PIN_SLEEPMODE_SHIFT) +#define PIN_SLEEPMODE_DISABLED (0 << PIN_SLEEPMODE_SHIFT) +#define PIN_SLEEPMODE_ENABLED (1 << PIN_SLEEPMODE_SHIFT) + + +/* Shortcuts. Use these instead of separate DIR, PULL, and VAL. */ +#define PIN_INPUT_PULLDOWN (PIN_DIR_INPUT | PIN_PULL_DOWN) +#define PIN_INPUT_PULLUP (PIN_DIR_INPUT | PIN_PULL_UP) +#define PIN_INPUT_NOPULL (PIN_DIR_INPUT | PIN_PULL_NONE) +#define PIN_OUTPUT_LOW (PIN_DIR_OUTPUT | PIN_VAL_LOW) +#define PIN_OUTPUT_HIGH (PIN_DIR_OUTPUT | PIN_VAL_HIGH) + +#define PIN_SLPM_INPUT_PULLDOWN (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_DOWN) +#define PIN_SLPM_INPUT_PULLUP (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_UP) +#define PIN_SLPM_INPUT_NOPULL (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_NONE) +#define PIN_SLPM_OUTPUT_LOW (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_LOW) +#define PIN_SLPM_OUTPUT_HIGH (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_HIGH) + +#define PIN_CFG_DEFAULT (0) + +#define PIN_CFG(num, alt) \ + (PIN_CFG_DEFAULT |\ + (PIN_NUM(num) | PIN_##alt)) + +#define PIN_CFG_INPUT(num, alt, pull) \ + (PIN_CFG_DEFAULT |\ + (PIN_NUM(num) | PIN_##alt | PIN_INPUT_##pull)) + +#define PIN_CFG_OUTPUT(num, alt, val) \ + (PIN_CFG_DEFAULT |\ + (PIN_NUM(num) | PIN_##alt | PIN_OUTPUT_##val)) + +/* + * "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving + * the "gpio" namespace for generic and cross-machine functions + */ + +#define GPIO_BLOCK_SHIFT 5 +#define NMK_GPIO_PER_CHIP (1 << GPIO_BLOCK_SHIFT) + +/* Register in the logic block */ +#define NMK_GPIO_DAT 0x00 +#define NMK_GPIO_DATS 0x04 +#define NMK_GPIO_DATC 0x08 +#define NMK_GPIO_PDIS 0x0c +#define NMK_GPIO_DIR 0x10 +#define NMK_GPIO_DIRS 0x14 +#define NMK_GPIO_DIRC 0x18 +#define NMK_GPIO_SLPC 0x1c +#define NMK_GPIO_AFSLA 0x20 +#define NMK_GPIO_AFSLB 0x24 +#define NMK_GPIO_LOWEMI 0x28 + +#define NMK_GPIO_RIMSC 0x40 +#define NMK_GPIO_FIMSC 0x44 +#define NMK_GPIO_IS 0x48 +#define NMK_GPIO_IC 0x4c +#define NMK_GPIO_RWIMSC 0x50 +#define NMK_GPIO_FWIMSC 0x54 +#define NMK_GPIO_WKS 0x58 +/* These appear in DB8540 and later ASICs */ +#define NMK_GPIO_EDGELEVEL 0x5C +#define NMK_GPIO_LEVEL 0x60 + + +/* Pull up/down values */ +enum nmk_gpio_pull { + NMK_GPIO_PULL_NONE, + NMK_GPIO_PULL_UP, + NMK_GPIO_PULL_DOWN, +}; + +/* Sleep mode */ +enum nmk_gpio_slpm { + NMK_GPIO_SLPM_INPUT, + NMK_GPIO_SLPM_WAKEUP_ENABLE = NMK_GPIO_SLPM_INPUT, + NMK_GPIO_SLPM_NOCHANGE, + NMK_GPIO_SLPM_WAKEUP_DISABLE = NMK_GPIO_SLPM_NOCHANGE, +}; + +/* + * Platform data to register a block: only the initial gpio/irq number. + */ +struct nmk_gpio_platform_data { + char *name; + int first_gpio; + int first_irq; + int num_gpio; + u32 (*get_secondary_status)(unsigned int bank); + void (*set_ioforce)(bool enable); + bool supports_sleepmode; +}; + struct nmk_gpio_chip { struct gpio_chip chip; struct irq_domain *domain; diff --git a/drivers/pinctrl/pinctrl-nomadik.h b/drivers/pinctrl/pinctrl-nomadik.h index bcd4191e10ea..d8215f1e70c7 100644 --- a/drivers/pinctrl/pinctrl-nomadik.h +++ b/drivers/pinctrl/pinctrl-nomadik.h @@ -1,13 +1,23 @@ #ifndef PINCTRL_PINCTRL_NOMADIK_H #define PINCTRL_PINCTRL_NOMADIK_H -#include - /* Package definitions */ #define PINCTRL_NMK_STN8815 0 #define PINCTRL_NMK_DB8500 1 #define PINCTRL_NMK_DB8540 2 +/* Alternate functions: function C is set in hw by setting both A and B */ +#define NMK_GPIO_ALT_GPIO 0 +#define NMK_GPIO_ALT_A 1 +#define NMK_GPIO_ALT_B 2 +#define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B) + +#define NMK_GPIO_ALT_CX_SHIFT 2 +#define NMK_GPIO_ALT_C1 ((1< - * Copyright (C) 2009 Alessandro Rubini - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __PLAT_NOMADIK_GPIO -#define __PLAT_NOMADIK_GPIO - -/* - * pin configurations are represented by 32-bit integers: - * - * bit 0.. 8 - Pin Number (512 Pins Maximum) - * bit 9..10 - Alternate Function Selection - * bit 11..12 - Pull up/down state - * bit 13 - Sleep mode behaviour - * bit 14 - Direction - * bit 15 - Value (if output) - * bit 16..18 - SLPM pull up/down state - * bit 19..20 - SLPM direction - * bit 21..22 - SLPM Value (if output) - * bit 23..25 - PDIS value (if input) - * bit 26 - Gpio mode - * bit 27 - Sleep mode - * - * to facilitate the definition, the following macros are provided - * - * PIN_CFG_DEFAULT - default config (0): - * pull up/down = disabled - * sleep mode = input/wakeup - * direction = input - * value = low - * SLPM direction = same as normal - * SLPM pull = same as normal - * SLPM value = same as normal - * - * PIN_CFG - default config with alternate function - */ - -typedef unsigned long pin_cfg_t; - -#define PIN_NUM_MASK 0x1ff -#define PIN_NUM(x) ((x) & PIN_NUM_MASK) - -#define PIN_ALT_SHIFT 9 -#define PIN_ALT_MASK (0x3 << PIN_ALT_SHIFT) -#define PIN_ALT(x) (((x) & PIN_ALT_MASK) >> PIN_ALT_SHIFT) -#define PIN_GPIO (NMK_GPIO_ALT_GPIO << PIN_ALT_SHIFT) -#define PIN_ALT_A (NMK_GPIO_ALT_A << PIN_ALT_SHIFT) -#define PIN_ALT_B (NMK_GPIO_ALT_B << PIN_ALT_SHIFT) -#define PIN_ALT_C (NMK_GPIO_ALT_C << PIN_ALT_SHIFT) - -#define PIN_PULL_SHIFT 11 -#define PIN_PULL_MASK (0x3 << PIN_PULL_SHIFT) -#define PIN_PULL(x) (((x) & PIN_PULL_MASK) >> PIN_PULL_SHIFT) -#define PIN_PULL_NONE (NMK_GPIO_PULL_NONE << PIN_PULL_SHIFT) -#define PIN_PULL_UP (NMK_GPIO_PULL_UP << PIN_PULL_SHIFT) -#define PIN_PULL_DOWN (NMK_GPIO_PULL_DOWN << PIN_PULL_SHIFT) - -#define PIN_SLPM_SHIFT 13 -#define PIN_SLPM_MASK (0x1 << PIN_SLPM_SHIFT) -#define PIN_SLPM(x) (((x) & PIN_SLPM_MASK) >> PIN_SLPM_SHIFT) -#define PIN_SLPM_MAKE_INPUT (NMK_GPIO_SLPM_INPUT << PIN_SLPM_SHIFT) -#define PIN_SLPM_NOCHANGE (NMK_GPIO_SLPM_NOCHANGE << PIN_SLPM_SHIFT) -/* These two replace the above in DB8500v2+ */ -#define PIN_SLPM_WAKEUP_ENABLE (NMK_GPIO_SLPM_WAKEUP_ENABLE << PIN_SLPM_SHIFT) -#define PIN_SLPM_WAKEUP_DISABLE (NMK_GPIO_SLPM_WAKEUP_DISABLE << PIN_SLPM_SHIFT) -#define PIN_SLPM_USE_MUX_SETTINGS_IN_SLEEP PIN_SLPM_WAKEUP_DISABLE - -#define PIN_SLPM_GPIO PIN_SLPM_WAKEUP_ENABLE /* In SLPM, pin is a gpio */ -#define PIN_SLPM_ALTFUNC PIN_SLPM_WAKEUP_DISABLE /* In SLPM, pin is altfunc */ - -#define PIN_DIR_SHIFT 14 -#define PIN_DIR_MASK (0x1 << PIN_DIR_SHIFT) -#define PIN_DIR(x) (((x) & PIN_DIR_MASK) >> PIN_DIR_SHIFT) -#define PIN_DIR_INPUT (0 << PIN_DIR_SHIFT) -#define PIN_DIR_OUTPUT (1 << PIN_DIR_SHIFT) - -#define PIN_VAL_SHIFT 15 -#define PIN_VAL_MASK (0x1 << PIN_VAL_SHIFT) -#define PIN_VAL(x) (((x) & PIN_VAL_MASK) >> PIN_VAL_SHIFT) -#define PIN_VAL_LOW (0 << PIN_VAL_SHIFT) -#define PIN_VAL_HIGH (1 << PIN_VAL_SHIFT) - -#define PIN_SLPM_PULL_SHIFT 16 -#define PIN_SLPM_PULL_MASK (0x7 << PIN_SLPM_PULL_SHIFT) -#define PIN_SLPM_PULL(x) \ - (((x) & PIN_SLPM_PULL_MASK) >> PIN_SLPM_PULL_SHIFT) -#define PIN_SLPM_PULL_NONE \ - ((1 + NMK_GPIO_PULL_NONE) << PIN_SLPM_PULL_SHIFT) -#define PIN_SLPM_PULL_UP \ - ((1 + NMK_GPIO_PULL_UP) << PIN_SLPM_PULL_SHIFT) -#define PIN_SLPM_PULL_DOWN \ - ((1 + NMK_GPIO_PULL_DOWN) << PIN_SLPM_PULL_SHIFT) - -#define PIN_SLPM_DIR_SHIFT 19 -#define PIN_SLPM_DIR_MASK (0x3 << PIN_SLPM_DIR_SHIFT) -#define PIN_SLPM_DIR(x) \ - (((x) & PIN_SLPM_DIR_MASK) >> PIN_SLPM_DIR_SHIFT) -#define PIN_SLPM_DIR_INPUT ((1 + 0) << PIN_SLPM_DIR_SHIFT) -#define PIN_SLPM_DIR_OUTPUT ((1 + 1) << PIN_SLPM_DIR_SHIFT) - -#define PIN_SLPM_VAL_SHIFT 21 -#define PIN_SLPM_VAL_MASK (0x3 << PIN_SLPM_VAL_SHIFT) -#define PIN_SLPM_VAL(x) \ - (((x) & PIN_SLPM_VAL_MASK) >> PIN_SLPM_VAL_SHIFT) -#define PIN_SLPM_VAL_LOW ((1 + 0) << PIN_SLPM_VAL_SHIFT) -#define PIN_SLPM_VAL_HIGH ((1 + 1) << PIN_SLPM_VAL_SHIFT) - -#define PIN_SLPM_PDIS_SHIFT 23 -#define PIN_SLPM_PDIS_MASK (0x3 << PIN_SLPM_PDIS_SHIFT) -#define PIN_SLPM_PDIS(x) \ - (((x) & PIN_SLPM_PDIS_MASK) >> PIN_SLPM_PDIS_SHIFT) -#define PIN_SLPM_PDIS_NO_CHANGE (0 << PIN_SLPM_PDIS_SHIFT) -#define PIN_SLPM_PDIS_DISABLED (1 << PIN_SLPM_PDIS_SHIFT) -#define PIN_SLPM_PDIS_ENABLED (2 << PIN_SLPM_PDIS_SHIFT) - -#define PIN_LOWEMI_SHIFT 25 -#define PIN_LOWEMI_MASK (0x1 << PIN_LOWEMI_SHIFT) -#define PIN_LOWEMI(x) (((x) & PIN_LOWEMI_MASK) >> PIN_LOWEMI_SHIFT) -#define PIN_LOWEMI_DISABLED (0 << PIN_LOWEMI_SHIFT) -#define PIN_LOWEMI_ENABLED (1 << PIN_LOWEMI_SHIFT) - -#define PIN_GPIOMODE_SHIFT 26 -#define PIN_GPIOMODE_MASK (0x1 << PIN_GPIOMODE_SHIFT) -#define PIN_GPIOMODE(x) (((x) & PIN_GPIOMODE_MASK) >> PIN_GPIOMODE_SHIFT) -#define PIN_GPIOMODE_DISABLED (0 << PIN_GPIOMODE_SHIFT) -#define PIN_GPIOMODE_ENABLED (1 << PIN_GPIOMODE_SHIFT) - -#define PIN_SLEEPMODE_SHIFT 27 -#define PIN_SLEEPMODE_MASK (0x1 << PIN_SLEEPMODE_SHIFT) -#define PIN_SLEEPMODE(x) (((x) & PIN_SLEEPMODE_MASK) >> PIN_SLEEPMODE_SHIFT) -#define PIN_SLEEPMODE_DISABLED (0 << PIN_SLEEPMODE_SHIFT) -#define PIN_SLEEPMODE_ENABLED (1 << PIN_SLEEPMODE_SHIFT) - - -/* Shortcuts. Use these instead of separate DIR, PULL, and VAL. */ -#define PIN_INPUT_PULLDOWN (PIN_DIR_INPUT | PIN_PULL_DOWN) -#define PIN_INPUT_PULLUP (PIN_DIR_INPUT | PIN_PULL_UP) -#define PIN_INPUT_NOPULL (PIN_DIR_INPUT | PIN_PULL_NONE) -#define PIN_OUTPUT_LOW (PIN_DIR_OUTPUT | PIN_VAL_LOW) -#define PIN_OUTPUT_HIGH (PIN_DIR_OUTPUT | PIN_VAL_HIGH) - -#define PIN_SLPM_INPUT_PULLDOWN (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_DOWN) -#define PIN_SLPM_INPUT_PULLUP (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_UP) -#define PIN_SLPM_INPUT_NOPULL (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_NONE) -#define PIN_SLPM_OUTPUT_LOW (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_LOW) -#define PIN_SLPM_OUTPUT_HIGH (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_HIGH) - -#define PIN_CFG_DEFAULT (0) - -#define PIN_CFG(num, alt) \ - (PIN_CFG_DEFAULT |\ - (PIN_NUM(num) | PIN_##alt)) - -#define PIN_CFG_INPUT(num, alt, pull) \ - (PIN_CFG_DEFAULT |\ - (PIN_NUM(num) | PIN_##alt | PIN_INPUT_##pull)) - -#define PIN_CFG_OUTPUT(num, alt, val) \ - (PIN_CFG_DEFAULT |\ - (PIN_NUM(num) | PIN_##alt | PIN_OUTPUT_##val)) - -/* - * "nmk_gpio" and "NMK_GPIO" stand for "Nomadik GPIO", leaving - * the "gpio" namespace for generic and cross-machine functions - */ - -#define GPIO_BLOCK_SHIFT 5 -#define NMK_GPIO_PER_CHIP (1 << GPIO_BLOCK_SHIFT) - -/* Register in the logic block */ -#define NMK_GPIO_DAT 0x00 -#define NMK_GPIO_DATS 0x04 -#define NMK_GPIO_DATC 0x08 -#define NMK_GPIO_PDIS 0x0c -#define NMK_GPIO_DIR 0x10 -#define NMK_GPIO_DIRS 0x14 -#define NMK_GPIO_DIRC 0x18 -#define NMK_GPIO_SLPC 0x1c -#define NMK_GPIO_AFSLA 0x20 -#define NMK_GPIO_AFSLB 0x24 -#define NMK_GPIO_LOWEMI 0x28 - -#define NMK_GPIO_RIMSC 0x40 -#define NMK_GPIO_FIMSC 0x44 -#define NMK_GPIO_IS 0x48 -#define NMK_GPIO_IC 0x4c -#define NMK_GPIO_RWIMSC 0x50 -#define NMK_GPIO_FWIMSC 0x54 -#define NMK_GPIO_WKS 0x58 -/* These appear in DB8540 and later ASICs */ -#define NMK_GPIO_EDGELEVEL 0x5C -#define NMK_GPIO_LEVEL 0x60 - -/* Alternate functions: function C is set in hw by setting both A and B */ -#define NMK_GPIO_ALT_GPIO 0 -#define NMK_GPIO_ALT_A 1 -#define NMK_GPIO_ALT_B 2 -#define NMK_GPIO_ALT_C (NMK_GPIO_ALT_A | NMK_GPIO_ALT_B) - -#define NMK_GPIO_ALT_CX_SHIFT 2 -#define NMK_GPIO_ALT_C1 ((1< Date: Tue, 19 Nov 2013 22:23:21 +0100 Subject: clksrc: delete nomadik MTU non-DT boot path Both platforms using the MTU (Nomadik and Ux500) have now been converted to use device tree exclusively, thus let us delete this platform data header and make this driver a fully self-contained DT-only driver. Cc: Thomas Gleixner Cc: Lee Jones Acked-by: Daniel Lezcano Signed-off-by: Linus Walleij --- drivers/clocksource/nomadik-mtu.c | 23 +++++----------------- .../linux/platform_data/clocksource-nomadik-mtu.h | 9 --------- 2 files changed, 5 insertions(+), 27 deletions(-) delete mode 100644 include/linux/platform_data/clocksource-nomadik-mtu.h (limited to 'include/linux') diff --git a/drivers/clocksource/nomadik-mtu.c b/drivers/clocksource/nomadik-mtu.c index ed7b73b508e0..f00b5c9ce8b6 100644 --- a/drivers/clocksource/nomadik-mtu.c +++ b/drivers/clocksource/nomadik-mtu.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -103,7 +102,7 @@ static int nmdk_clkevt_next(unsigned long evt, struct clock_event_device *ev) return 0; } -void nmdk_clkevt_reset(void) +static void nmdk_clkevt_reset(void) { if (clkevt_periodic) { /* Timer: configure load and background-load, and fire it up */ @@ -144,7 +143,7 @@ static void nmdk_clkevt_mode(enum clock_event_mode mode, } } -void nmdk_clksrc_reset(void) +static void nmdk_clksrc_reset(void) { /* Disable */ writel(0, mtu_base + MTU_CR(0)); @@ -192,8 +191,8 @@ static struct irqaction nmdk_timer_irq = { .dev_id = &nmdk_clkevt, }; -static void __init __nmdk_timer_init(void __iomem *base, int irq, - struct clk *pclk, struct clk *clk) +static void __init nmdk_timer_init(void __iomem *base, int irq, + struct clk *pclk, struct clk *clk) { unsigned long rate; @@ -245,18 +244,6 @@ static void __init __nmdk_timer_init(void __iomem *base, int irq, register_current_timer_delay(&mtu_delay_timer); } -void __init nmdk_timer_init(void __iomem *base, int irq) -{ - struct clk *clk0, *pclk0; - - pclk0 = clk_get_sys("mtu0", "apb_pclk"); - BUG_ON(IS_ERR(pclk0)); - clk0 = clk_get_sys("mtu0", NULL); - BUG_ON(IS_ERR(clk0)); - - __nmdk_timer_init(base, irq, pclk0, clk0); -} - static void __init nmdk_timer_of_init(struct device_node *node) { struct clk *pclk; @@ -280,7 +267,7 @@ static void __init nmdk_timer_of_init(struct device_node *node) if (irq <= 0) panic("Can't parse IRQ"); - __nmdk_timer_init(base, irq, pclk, clk); + nmdk_timer_init(base, irq, pclk, clk); } CLOCKSOURCE_OF_DECLARE(nomadik_mtu, "st,nomadik-mtu", nmdk_timer_of_init); diff --git a/include/linux/platform_data/clocksource-nomadik-mtu.h b/include/linux/platform_data/clocksource-nomadik-mtu.h deleted file mode 100644 index 80088973b734..000000000000 --- a/include/linux/platform_data/clocksource-nomadik-mtu.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __PLAT_MTU_H -#define __PLAT_MTU_H - -void nmdk_timer_init(void __iomem *base, int irq); -void nmdk_clkevt_reset(void); -void nmdk_clksrc_reset(void); - -#endif /* __PLAT_MTU_H */ - -- cgit v1.2.3-59-g8ed1b From 261000a56b6382f597bcb12000f55c9ff26a1efb Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 25 May 2012 18:37:55 -0600 Subject: userns: userns: Remove UIDGID_STRICT_TYPE_CHECKS Removing UIDGID_STRICT_TYPE_CHECKS simplifies the code and always generates a compile error if the uids and kuids or gids and kgids are mixed by accident. Now that the appropriate conversions have been placed throughout the kernel there is no longer a need for a mode where we don't detect them as compile errors. Acked-by: Serge Hallyn Signed-off-by: Eric W. Biederman --- include/linux/posix_acl.h | 3 --- include/linux/projid.h | 15 --------------- include/linux/uidgid.h | 22 ---------------------- init/Kconfig | 11 ----------- 4 files changed, 51 deletions(-) (limited to 'include/linux') diff --git a/include/linux/posix_acl.h b/include/linux/posix_acl.h index 7931efe71175..f0f7746b2359 100644 --- a/include/linux/posix_acl.h +++ b/include/linux/posix_acl.h @@ -39,9 +39,6 @@ struct posix_acl_entry { union { kuid_t e_uid; kgid_t e_gid; -#ifndef CONFIG_UIDGID_STRICT_TYPE_CHECKS - unsigned int e_id; -#endif }; }; diff --git a/include/linux/projid.h b/include/linux/projid.h index 36517b95be5c..8c1f2c55226d 100644 --- a/include/linux/projid.h +++ b/include/linux/projid.h @@ -18,8 +18,6 @@ extern struct user_namespace init_user_ns; typedef __kernel_uid32_t projid_t; -#ifdef CONFIG_UIDGID_STRICT_TYPE_CHECKS - typedef struct { projid_t val; } kprojid_t; @@ -31,19 +29,6 @@ static inline projid_t __kprojid_val(kprojid_t projid) #define KPROJIDT_INIT(value) (kprojid_t){ value } -#else - -typedef projid_t kprojid_t; - -static inline projid_t __kprojid_val(kprojid_t projid) -{ - return projid; -} - -#define KPROJIDT_INIT(value) ((kprojid_t) value ) - -#endif - #define INVALID_PROJID KPROJIDT_INIT(-1) #define OVERFLOW_PROJID 65534 diff --git a/include/linux/uidgid.h b/include/linux/uidgid.h index 8e522cbcef29..2d1f9b627f91 100644 --- a/include/linux/uidgid.h +++ b/include/linux/uidgid.h @@ -17,8 +17,6 @@ struct user_namespace; extern struct user_namespace init_user_ns; -#ifdef CONFIG_UIDGID_STRICT_TYPE_CHECKS - typedef struct { uid_t val; } kuid_t; @@ -41,26 +39,6 @@ static inline gid_t __kgid_val(kgid_t gid) return gid.val; } -#else - -typedef uid_t kuid_t; -typedef gid_t kgid_t; - -static inline uid_t __kuid_val(kuid_t uid) -{ - return uid; -} - -static inline gid_t __kgid_val(kgid_t gid) -{ - return gid; -} - -#define KUIDT_INIT(value) ((kuid_t) value ) -#define KGIDT_INIT(value) ((kgid_t) value ) - -#endif - #define GLOBAL_ROOT_UID KUIDT_INIT(0) #define GLOBAL_ROOT_GID KGIDT_INIT(0) diff --git a/init/Kconfig b/init/Kconfig index 79383d3aa5dc..d4eb994d1757 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1110,8 +1110,6 @@ config IPC_NS config USER_NS bool "User namespace" - select UIDGID_STRICT_TYPE_CHECKS - default n help This allows containers, i.e. vservers, to use user namespaces @@ -1143,15 +1141,6 @@ config NET_NS endif # NAMESPACES -config UIDGID_STRICT_TYPE_CHECKS - bool "Require conversions between uid/gids and their internal representation" - default n - help - While the nececessary conversions are being added to all subsystems this option allows - the code to continue to build for unconverted subsystems. - - Say Y here if you want the strict type checking enabled - config SCHED_AUTOGROUP bool "Automatic process group scheduling" select EVENTFD -- cgit v1.2.3-59-g8ed1b From 71ad88efebbcde374bddf904b96f3a7fc82d45d4 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 12 Nov 2013 17:58:48 +0100 Subject: perf: Add active_entry list head to struct perf_event This patch adds a new field to the struct perf_event. It is intended to be used to chain events which are active (enabled). It helps in the hardware layer for PMUs which do not have actual counter restrictions, i.e., free running read-only counters. Active events are chained as opposed to being tracked via the counter they use. To save space we use a union with hlist_entry as both are mutually exclusive (suggested by Jiri Olsa). Signed-off-by: Stephane Eranian Reviewed-by: Andi Kleen Signed-off-by: Peter Zijlstra Cc: acme@redhat.com Cc: jolsa@redhat.com Cc: zheng.z.yan@intel.com Cc: bp@alien8.de Cc: maria.n.dimakopoulou@gmail.com Link: http://lkml.kernel.org/r/1384275531-10892-2-git-send-email-eranian@google.com Signed-off-by: Ingo Molnar --- include/linux/perf_event.h | 5 ++++- kernel/events/core.c | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 2e069d1288df..8f4a70f2eca8 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -319,7 +319,10 @@ struct perf_event { */ struct list_head migrate_entry; - struct hlist_node hlist_entry; + union { + struct hlist_node hlist_entry; + struct list_head active_entry; + }; int nr_siblings; int group_flags; struct perf_event *group_leader; diff --git a/kernel/events/core.c b/kernel/events/core.c index 72348dc192c1..403b781daafb 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6655,6 +6655,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, INIT_LIST_HEAD(&event->event_entry); INIT_LIST_HEAD(&event->sibling_list); INIT_LIST_HEAD(&event->rb_entry); + INIT_LIST_HEAD(&event->active_entry); init_waitqueue_head(&event->waitq); init_irq_work(&event->pending, perf_pending_event); -- cgit v1.2.3-59-g8ed1b From 86506a99a62400e9f7b7d1344bcc9ea235faf98f Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 13 Nov 2013 15:36:14 +0100 Subject: tasks/exit: Remove unused task_is_dead() method task_is_dead() has no users since commit 43e13cc107cf ("cred: remove task_is_dead() from __task_cred() validation"), and nobody except exit.c should rely on ->exit_state (we still have the users which should be changed). Signed-off-by: Oleg Nesterov Signed-off-by: Peter Zijlstra Cc: David Laight Cc: Geert Uytterhoeven Cc: Tejun Heo Cc: Andrew Morton Cc: Linus Torvalds Link: http://lkml.kernel.org/r/20131113143614.GA10547@redhat.com Signed-off-by: Ingo Molnar --- include/linux/sched.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/sched.h b/include/linux/sched.h index 7e35d4b9e14a..cda8d634bc47 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -168,7 +168,6 @@ extern char ___assert_task_state[1 - 2*!!( #define task_is_traced(task) ((task->state & __TASK_TRACED) != 0) #define task_is_stopped(task) ((task->state & __TASK_STOPPED) != 0) -#define task_is_dead(task) ((task)->exit_state != 0) #define task_is_stopped_or_traced(task) \ ((task->state & (__TASK_STOPPED | __TASK_TRACED)) != 0) #define task_contributes_to_load(task) \ -- cgit v1.2.3-59-g8ed1b From c84a3b27798dfce928b867fa1c9f3c3fd66f0a31 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 23 Nov 2013 18:01:46 -0500 Subject: sysfs: drop kobj_ns_type handling, take #2 The way namespace tags are implemented in sysfs is more complicated than necessary. As each tag is a pointer value and required to be non-NULL under a namespace enabled parent, there's no need to record separately what type each tag is. If multiple namespace types are needed, which currently aren't, we can simply compare the tag to a set of allowed tags in the superblock assuming that the tags, being pointers, won't have the same value across multiple types. This patch rips out kobj_ns_type handling from sysfs. sysfs now has an enable switch to turn on namespace under a node. If enabled, all children are required to have non-NULL namespace tags and filtered against the super_block's tag. kobject namespace determination is now performed in lib/kobject.c::create_dir() making sysfs_read_ns_type() unnecessary. The sanity checks are also moved. create_dir() is restructured to ease such addition. This removes most kobject namespace knowledge from sysfs proper which will enable proper separation and layering of sysfs. This is the second try. The first one was cb26a311578e ("sysfs: drop kobj_ns_type handling") which tried to automatically enable namespace if there are children with non-NULL namespace tags; however, it was broken for symlinks as they should inherit the target's tag iff namespace is enabled in the parent. This led to namespace filtering enabled incorrectly for wireless net class devices through phy80211 symlinks and thus network configuration failure. a1212d278c05 ("Revert "sysfs: drop kobj_ns_type handling"") reverted the commit. This shouldn't introduce any behavior changes, for real. v2: Dummy implementation of sysfs_enable_ns() for !CONFIG_SYSFS was missing and caused build failure. Reported by kbuild test robot. Signed-off-by: Tejun Heo Reported-by: Linus Torvalds Cc: Eric W. Biederman Cc: Kay Sievers Cc: Greg Kroah-Hartman Cc: kbuild test robot Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 92 ++++++++++++++++++++------------------------------- fs/sysfs/mount.c | 24 ++++---------- fs/sysfs/symlink.c | 26 ++++----------- fs/sysfs/sysfs.h | 25 ++++---------- include/linux/sysfs.h | 6 ++++ lib/kobject.c | 27 ++++++++++++--- 6 files changed, 83 insertions(+), 117 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 5e73d6626e50..b3cf61dc57c1 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -279,7 +279,6 @@ static int sysfs_dentry_delete(const struct dentry *dentry) static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) { struct sysfs_dirent *sd; - int type; if (flags & LOOKUP_RCU) return -ECHILD; @@ -300,13 +299,9 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) goto out_bad; /* The sysfs dirent has been moved to a different namespace */ - type = KOBJ_NS_TYPE_NONE; - if (sd->s_parent) { - type = sysfs_ns_type(sd->s_parent); - if (type != KOBJ_NS_TYPE_NONE && - sysfs_info(dentry->d_sb)->ns[type] != sd->s_ns) - goto out_bad; - } + if (sd->s_parent && (sd->s_parent->s_flags & SYSFS_FLAG_NS) && + sysfs_info(dentry->d_sb)->ns != sd->s_ns) + goto out_bad; mutex_unlock(&sysfs_mutex); out_valid: @@ -423,13 +418,14 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt) int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, struct sysfs_dirent *parent_sd) { + bool has_ns = parent_sd->s_flags & SYSFS_FLAG_NS; struct sysfs_inode_attrs *ps_iattr; int ret; - if (!!sysfs_ns_type(parent_sd) != !!sd->s_ns) { + if (has_ns != (bool)sd->s_ns) { WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", - sysfs_ns_type(parent_sd) ? "required" : "invalid", - parent_sd->s_name, sd->s_name); + has_ns ? "required" : "invalid", + parent_sd->s_name, sd->s_name); return -EINVAL; } @@ -610,12 +606,13 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, const void *ns) { struct rb_node *node = parent_sd->s_dir.children.rb_node; + bool has_ns = parent_sd->s_flags & SYSFS_FLAG_NS; unsigned int hash; - if (!!sysfs_ns_type(parent_sd) != !!ns) { + if (has_ns != (bool)ns) { WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", - sysfs_ns_type(parent_sd) ? "required" : "invalid", - parent_sd->s_name, name); + has_ns ? "required" : "invalid", + parent_sd->s_name, name); return NULL; } @@ -667,7 +664,6 @@ struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns); static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, - enum kobj_ns_type type, const char *name, const void *ns, struct sysfs_dirent **p_sd) { @@ -681,7 +677,6 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, if (!sd) return -ENOMEM; - sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT); sd->s_ns = ns; sd->s_dir.kobj = kobj; @@ -701,33 +696,7 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, int sysfs_create_subdir(struct kobject *kobj, const char *name, struct sysfs_dirent **p_sd) { - return create_dir(kobj, kobj->sd, - KOBJ_NS_TYPE_NONE, name, NULL, p_sd); -} - -/** - * sysfs_read_ns_type: return associated ns_type - * @kobj: the kobject being queried - * - * Each kobject can be tagged with exactly one namespace type - * (i.e. network or user). Return the ns_type associated with - * this object if any - */ -static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj) -{ - const struct kobj_ns_type_operations *ops; - enum kobj_ns_type type; - - ops = kobj_child_ns_ops(kobj); - if (!ops) - return KOBJ_NS_TYPE_NONE; - - type = ops->type; - BUG_ON(type <= KOBJ_NS_TYPE_NONE); - BUG_ON(type >= KOBJ_NS_TYPES); - BUG_ON(!kobj_ns_type_registered(type)); - - return type; + return create_dir(kobj, kobj->sd, name, NULL, p_sd); } /** @@ -737,7 +706,6 @@ static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj) */ int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) { - enum kobj_ns_type type; struct sysfs_dirent *parent_sd, *sd; int error = 0; @@ -751,9 +719,7 @@ int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) if (!parent_sd) return -ENOENT; - type = sysfs_read_ns_type(kobj); - - error = create_dir(kobj, parent_sd, type, kobject_name(kobj), ns, &sd); + error = create_dir(kobj, parent_sd, kobject_name(kobj), ns, &sd); if (!error) kobj->sd = sd; return error; @@ -767,13 +733,12 @@ static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry, struct sysfs_dirent *parent_sd = parent->d_fsdata; struct sysfs_dirent *sd; struct inode *inode; - enum kobj_ns_type type; - const void *ns; + const void *ns = NULL; mutex_lock(&sysfs_mutex); - type = sysfs_ns_type(parent_sd); - ns = sysfs_info(dir->i_sb)->ns[type]; + if (parent_sd->s_flags & SYSFS_FLAG_NS) + ns = sysfs_info(dir->i_sb)->ns; sd = sysfs_find_dirent(parent_sd, dentry->d_name.name, ns); @@ -1029,6 +994,21 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, return sysfs_rename(sd, new_parent_sd, sd->s_name, new_ns); } +/** + * sysfs_enable_ns - enable namespace under a directory + * @sd: directory of interest, should be empty + * + * This is to be called right after @sd is created to enable namespace + * under it. All children of @sd must have non-NULL namespace tags and + * only the ones which match the super_block's tag will be visible. + */ +void sysfs_enable_ns(struct sysfs_dirent *sd) +{ + WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); + WARN_ON_ONCE(!RB_EMPTY_ROOT(&sd->s_dir.children)); + sd->s_flags |= SYSFS_FLAG_NS; +} + /* Relationship between s_mode and the DT_xxx types */ static inline unsigned char dt_type(struct sysfs_dirent *sd) { @@ -1096,15 +1076,15 @@ static int sysfs_readdir(struct file *file, struct dir_context *ctx) struct dentry *dentry = file->f_path.dentry; struct sysfs_dirent *parent_sd = dentry->d_fsdata; struct sysfs_dirent *pos = file->private_data; - enum kobj_ns_type type; - const void *ns; - - type = sysfs_ns_type(parent_sd); - ns = sysfs_info(dentry->d_sb)->ns[type]; + const void *ns = NULL; if (!dir_emit_dots(file, ctx)) return 0; mutex_lock(&sysfs_mutex); + + if (parent_sd->s_flags & SYSFS_FLAG_NS) + ns = sysfs_info(dentry->d_sb)->ns; + for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos); pos; pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) { diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 834ec2cdb7a3..8c24bce2f4ae 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -36,7 +36,7 @@ static const struct super_operations sysfs_ops = { struct sysfs_dirent sysfs_root = { .s_name = "", .s_count = ATOMIC_INIT(1), - .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT), + .s_flags = SYSFS_DIR, .s_mode = S_IFDIR | S_IRUGO | S_IXUGO, .s_ino = 1, }; @@ -77,14 +77,8 @@ static int sysfs_test_super(struct super_block *sb, void *data) { struct sysfs_super_info *sb_info = sysfs_info(sb); struct sysfs_super_info *info = data; - enum kobj_ns_type type; - int found = 1; - for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { - if (sb_info->ns[type] != info->ns[type]) - found = 0; - } - return found; + return sb_info->ns == info->ns; } static int sysfs_set_super(struct super_block *sb, void *data) @@ -98,9 +92,7 @@ static int sysfs_set_super(struct super_block *sb, void *data) static void free_sysfs_super_info(struct sysfs_super_info *info) { - int type; - for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) - kobj_ns_drop(type, info->ns[type]); + kobj_ns_drop(KOBJ_NS_TYPE_NET, info->ns); kfree(info); } @@ -108,7 +100,6 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { struct sysfs_super_info *info; - enum kobj_ns_type type; struct super_block *sb; int error; @@ -116,18 +107,15 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) return ERR_PTR(-EPERM); - for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { - if (!kobj_ns_current_may_mount(type)) - return ERR_PTR(-EPERM); - } + if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) + return ERR_PTR(-EPERM); } info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return ERR_PTR(-ENOMEM); - for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) - info->ns[type] = kobj_ns_grab_current(type); + info->ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); if (IS_ERR(sb) || sb->s_fs_info != info) diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 3ae3f1bf1a09..c660363fdaea 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -28,7 +28,6 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, struct sysfs_dirent *target_sd = NULL; struct sysfs_dirent *sd = NULL; struct sysfs_addrm_cxt acxt; - enum kobj_ns_type ns_type; int error; BUG_ON(!name || !parent_sd); @@ -52,29 +51,16 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, if (!sd) goto out_put; - ns_type = sysfs_ns_type(parent_sd); - if (ns_type) + if (parent_sd->s_flags & SYSFS_FLAG_NS) sd->s_ns = target_sd->s_ns; sd->s_symlink.target_sd = target_sd; target_sd = NULL; /* reference is now owned by the symlink */ sysfs_addrm_start(&acxt); - /* Symlinks must be between directories with the same ns_type */ - if (!ns_type || - (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) { - if (warn) - error = sysfs_add_one(&acxt, sd, parent_sd); - else - error = __sysfs_add_one(&acxt, sd, parent_sd); - } else { - error = -EINVAL; - WARN(1, KERN_WARNING - "sysfs: symlink across ns_types %s/%s -> %s/%s\n", - parent_sd->s_name, - sd->s_name, - sd->s_symlink.target_sd->s_parent->s_name, - sd->s_symlink.target_sd->s_name); - } + if (warn) + error = sysfs_add_one(&acxt, sd, parent_sd); + else + error = __sysfs_add_one(&acxt, sd, parent_sd); sysfs_addrm_finish(&acxt); if (error) @@ -164,7 +150,7 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, * sysfs_remove_dir() for details. */ spin_lock(&sysfs_symlink_target_lock); - if (targ->sd && sysfs_ns_type(kobj->sd)) + if (targ->sd && (kobj->sd->s_flags & SYSFS_FLAG_NS)) ns = targ->sd->s_ns; spin_unlock(&sysfs_symlink_target_lock); sysfs_hash_and_remove(kobj->sd, name, ns); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 0af09fbfb3f6..e116c21a27bf 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -90,11 +90,8 @@ struct sysfs_dirent { #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) #define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) -/* identify any namespace tag on sysfs_dirents */ -#define SYSFS_NS_TYPE_MASK 0xf00 -#define SYSFS_NS_TYPE_SHIFT 8 - -#define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK) +#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK +#define SYSFS_FLAG_NS 0x01000 #define SYSFS_FLAG_REMOVED 0x02000 static inline unsigned int sysfs_type(struct sysfs_dirent *sd) @@ -102,15 +99,6 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd) return sd->s_flags & SYSFS_TYPE_MASK; } -/* - * Return any namespace tags on this dirent. - * enum kobj_ns_type is defined in linux/kobject.h - */ -static inline enum kobj_ns_type sysfs_ns_type(struct sysfs_dirent *sd) -{ - return (sd->s_flags & SYSFS_NS_TYPE_MASK) >> SYSFS_NS_TYPE_SHIFT; -} - #ifdef CONFIG_DEBUG_LOCK_ALLOC #define sysfs_dirent_init_lockdep(sd) \ @@ -155,12 +143,13 @@ struct sysfs_addrm_cxt { */ /* - * Each sb is associated with a set of namespace tags (i.e. - * the network namespace of the task which mounted this sysfs - * instance). + * Each sb is associated with one namespace tag, currently the network + * namespace of the task which mounted this sysfs instance. If multiple + * tags become necessary, make the following an array and compare + * sysfs_dirent tag against every entry. */ struct sysfs_super_info { - void *ns[KOBJ_NS_TYPES]; + void *ns; }; #define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) extern struct sysfs_dirent sysfs_root; diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 6695040a0317..362a34d27e64 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -220,6 +220,8 @@ int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *target, void sysfs_delete_link(struct kobject *dir, struct kobject *targ, const char *name); +void sysfs_enable_ns(struct sysfs_dirent *sd); + int __must_check sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp); int __must_check sysfs_create_groups(struct kobject *kobj, @@ -353,6 +355,10 @@ static inline void sysfs_delete_link(struct kobject *k, struct kobject *t, { } +static inline void sysfs_enable_ns(struct sysfs_dirent *sd) +{ +} + static inline int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp) { diff --git a/lib/kobject.c b/lib/kobject.c index 5b4b8886435e..16e9335b32d3 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -65,13 +65,17 @@ static int populate_dir(struct kobject *kobj) static int create_dir(struct kobject *kobj) { + const struct kobj_ns_type_operations *ops; int error; error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj)); - if (!error) { - error = populate_dir(kobj); - if (error) - sysfs_remove_dir(kobj); + if (error) + return error; + + error = populate_dir(kobj); + if (error) { + sysfs_remove_dir(kobj); + return error; } /* @@ -80,7 +84,20 @@ static int create_dir(struct kobject *kobj) */ sysfs_get(kobj->sd); - return error; + /* + * If @kobj has ns_ops, its children need to be filtered based on + * their namespace tags. Enable namespace support on @kobj->sd. + */ + ops = kobj_child_ns_ops(kobj); + if (ops) { + BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE); + BUG_ON(ops->type >= KOBJ_NS_TYPES); + BUG_ON(!kobj_ns_type_registered(ops->type)); + + sysfs_enable_ns(kobj->sd); + } + + return 0; } static int get_kobj_path_length(struct kobject *kobj) -- cgit v1.2.3-59-g8ed1b From b8441ed279bff09a0a5ddeacf8f4087d2fb424ca Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sun, 24 Nov 2013 09:54:58 -0500 Subject: sysfs, kernfs: add skeletons for kernfs Core sysfs implementation will be separated into kernfs so that it can be used by other non-kobject users. This patch creates fs/kernfs/ directory and makes boilerplate changes. kernfs interface will be directly based on sysfs_dirent and its forward declaration is moved to include/linux/kernfs.h which is included from include/linux/sysfs.h. sysfs core implementation will be gradually separated out and moved to kernfs. This patch doesn't introduce any functional changes. v2: mount.c added. Signed-off-by: Tejun Heo Cc: linux-fsdevel@vger.kernel.org Cc: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- fs/Makefile | 2 +- fs/kernfs/Makefile | 5 +++++ fs/kernfs/dir.c | 9 +++++++++ fs/kernfs/file.c | 9 +++++++++ fs/kernfs/inode.c | 9 +++++++++ fs/kernfs/mount.c | 9 +++++++++ fs/kernfs/symlink.c | 9 +++++++++ include/linux/kernfs.h | 12 ++++++++++++ include/linux/sysfs.h | 3 +-- 9 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 fs/kernfs/Makefile create mode 100644 fs/kernfs/dir.c create mode 100644 fs/kernfs/file.c create mode 100644 fs/kernfs/inode.c create mode 100644 fs/kernfs/mount.c create mode 100644 fs/kernfs/symlink.c create mode 100644 include/linux/kernfs.h (limited to 'include/linux') diff --git a/fs/Makefile b/fs/Makefile index 4fe6df3ec28f..39a824f44e7c 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -53,7 +53,7 @@ obj-$(CONFIG_FHANDLE) += fhandle.o obj-y += quota/ obj-$(CONFIG_PROC_FS) += proc/ -obj-$(CONFIG_SYSFS) += sysfs/ +obj-$(CONFIG_SYSFS) += sysfs/ kernfs/ obj-$(CONFIG_CONFIGFS_FS) += configfs/ obj-y += devpts/ diff --git a/fs/kernfs/Makefile b/fs/kernfs/Makefile new file mode 100644 index 000000000000..674337c76673 --- /dev/null +++ b/fs/kernfs/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the kernfs pseudo filesystem +# + +obj-y := mount.o inode.o dir.o file.o symlink.o diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c new file mode 100644 index 000000000000..1061602ce81a --- /dev/null +++ b/fs/kernfs/dir.c @@ -0,0 +1,9 @@ +/* + * fs/kernfs/dir.c - kernfs directory implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007, 2013 Tejun Heo + * + * This file is released under the GPLv2. + */ diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c new file mode 100644 index 000000000000..90b1e88dad44 --- /dev/null +++ b/fs/kernfs/file.c @@ -0,0 +1,9 @@ +/* + * fs/kernfs/file.c - kernfs file implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007, 2013 Tejun Heo + * + * This file is released under the GPLv2. + */ diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c new file mode 100644 index 000000000000..86bfeea07de2 --- /dev/null +++ b/fs/kernfs/inode.c @@ -0,0 +1,9 @@ +/* + * fs/kernfs/inode.c - kernfs inode implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007, 2013 Tejun Heo + * + * This file is released under the GPLv2. + */ diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c new file mode 100644 index 000000000000..872e262e5166 --- /dev/null +++ b/fs/kernfs/mount.c @@ -0,0 +1,9 @@ +/* + * fs/kernfs/mount.c - kernfs mount implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007, 2013 Tejun Heo + * + * This file is released under the GPLv2. + */ diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c new file mode 100644 index 000000000000..2578715baf0e --- /dev/null +++ b/fs/kernfs/symlink.c @@ -0,0 +1,9 @@ +/* + * fs/kernfs/symlink.c - kernfs symlink implementation + * + * Copyright (c) 2001-3 Patrick Mochel + * Copyright (c) 2007 SUSE Linux Products GmbH + * Copyright (c) 2007, 2013 Tejun Heo + * + * This file is released under the GPLv2. + */ diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h new file mode 100644 index 000000000000..254b9e872b09 --- /dev/null +++ b/include/linux/kernfs.h @@ -0,0 +1,12 @@ +/* + * kernfs.h - pseudo filesystem decoupled from vfs locking + * + * This file is released under the GPLv2. + */ + +#ifndef __LINUX_KERNFS_H +#define __LINUX_KERNFS_H + +struct sysfs_dirent; + +#endif /* __LINUX_KERNFS_H */ diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 362a34d27e64..e17381a92e1a 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -12,6 +12,7 @@ #ifndef _SYSFS_H_ #define _SYSFS_H_ +#include #include #include #include @@ -175,8 +176,6 @@ struct sysfs_ops { ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); }; -struct sysfs_dirent; - #ifdef CONFIG_SYSFS int sysfs_schedule_callback(struct kobject *kobj, void (*func)(void *), -- cgit v1.2.3-59-g8ed1b From 879f40d193bb3c6c13930e88e3e9d5d7baf84d19 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 23 Nov 2013 17:21:49 -0500 Subject: sysfs, kernfs: introduce kernfs_remove[_by_name[_ns]]() Introduce kernfs removal interfaces - kernfs_remove() and kernfs_remove_by_name[_ns](). These are just renames of sysfs_remove() and sysfs_hash_and_remove(). No functional changes. v2: Dummy kernfs_remove_by_name_ns() for !CONFIG_SYSFS updated to return -ENOSYS instead of 0. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 20 ++++++++++---------- fs/sysfs/file.c | 6 +++--- fs/sysfs/group.c | 15 +++++++-------- fs/sysfs/symlink.c | 4 ++-- fs/sysfs/sysfs.h | 3 --- include/linux/kernfs.h | 24 ++++++++++++++++++++++++ 6 files changed, 46 insertions(+), 26 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 98701c00b9b0..edbde4e6e5e0 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -829,8 +829,8 @@ static struct sysfs_dirent *sysfs_next_descendant_post(struct sysfs_dirent *pos, return pos->s_parent; } -static void __sysfs_remove(struct sysfs_addrm_cxt *acxt, - struct sysfs_dirent *sd) +static void __kernfs_remove(struct sysfs_addrm_cxt *acxt, + struct sysfs_dirent *sd) { struct sysfs_dirent *pos, *next; @@ -849,22 +849,22 @@ static void __sysfs_remove(struct sysfs_addrm_cxt *acxt, } /** - * sysfs_remove - remove a sysfs_dirent recursively + * kernfs_remove - remove a sysfs_dirent recursively * @sd: the sysfs_dirent to remove * * Remove @sd along with all its subdirectories and files. */ -void sysfs_remove(struct sysfs_dirent *sd) +void kernfs_remove(struct sysfs_dirent *sd) { struct sysfs_addrm_cxt acxt; sysfs_addrm_start(&acxt); - __sysfs_remove(&acxt, sd); + __kernfs_remove(&acxt, sd); sysfs_addrm_finish(&acxt); } /** - * sysfs_hash_and_remove - find a sysfs_dirent by name and remove it + * kernfs_remove_by_name_ns - find a sysfs_dirent by name and remove it * @dir_sd: parent of the target * @name: name of the sysfs_dirent to remove * @ns: namespace tag of the sysfs_dirent to remove @@ -872,8 +872,8 @@ void sysfs_remove(struct sysfs_dirent *sd) * Look for the sysfs_dirent with @name and @ns under @dir_sd and remove * it. Returns 0 on success, -ENOENT if such entry doesn't exist. */ -int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name, - const void *ns) +int kernfs_remove_by_name_ns(struct sysfs_dirent *dir_sd, const char *name, + const void *ns) { struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; @@ -888,7 +888,7 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name, sd = sysfs_find_dirent(dir_sd, name, ns); if (sd) - __sysfs_remove(&acxt, sd); + __kernfs_remove(&acxt, sd); sysfs_addrm_finish(&acxt); @@ -928,7 +928,7 @@ void sysfs_remove_dir(struct kobject *kobj) if (sd) { WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); - sysfs_remove(sd); + kernfs_remove(sd); } } diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 79b5da2acbe1..5664410136ba 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -952,7 +952,7 @@ void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr, { struct sysfs_dirent *dir_sd = kobj->sd; - sysfs_hash_and_remove(dir_sd, attr->name, ns); + kernfs_remove_by_name_ns(dir_sd, attr->name, ns); } EXPORT_SYMBOL_GPL(sysfs_remove_file_ns); @@ -980,7 +980,7 @@ void sysfs_remove_file_from_group(struct kobject *kobj, else dir_sd = sysfs_get(kobj->sd); if (dir_sd) { - sysfs_hash_and_remove(dir_sd, attr->name, NULL); + kernfs_remove_by_name(dir_sd, attr->name); sysfs_put(dir_sd); } } @@ -1008,7 +1008,7 @@ EXPORT_SYMBOL_GPL(sysfs_create_bin_file); void sysfs_remove_bin_file(struct kobject *kobj, const struct bin_attribute *attr) { - sysfs_hash_and_remove(kobj->sd, attr->attr.name, NULL); + kernfs_remove_by_name(kobj->sd, attr->attr.name); } EXPORT_SYMBOL_GPL(sysfs_remove_bin_file); diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 1898a10e38ce..4bd997340830 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -26,7 +26,7 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, if (grp->attrs) for (attr = grp->attrs; *attr; attr++) - sysfs_hash_and_remove(dir_sd, (*attr)->name, NULL); + kernfs_remove_by_name(dir_sd, (*attr)->name); if (grp->bin_attrs) for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) sysfs_remove_bin_file(kobj, *bin_attr); @@ -49,8 +49,7 @@ static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, * re-adding (if required) the file. */ if (update) - sysfs_hash_and_remove(dir_sd, (*attr)->name, - NULL); + kernfs_remove_by_name(dir_sd, (*attr)->name); if (grp->is_visible) { mode = grp->is_visible(kobj, *attr, i); if (!mode) @@ -111,7 +110,7 @@ static int internal_create_group(struct kobject *kobj, int update, error = create_files(sd, kobj, grp, update); if (error) { if (grp->name) - sysfs_remove(sd); + kernfs_remove(sd); } sysfs_put(sd); return error; @@ -219,7 +218,7 @@ void sysfs_remove_group(struct kobject *kobj, remove_files(sd, kobj, grp); if (grp->name) - sysfs_remove(sd); + kernfs_remove(sd); sysfs_put(sd); } @@ -270,7 +269,7 @@ int sysfs_merge_group(struct kobject *kobj, error = sysfs_add_file(dir_sd, *attr, SYSFS_KOBJ_ATTR); if (error) { while (--i >= 0) - sysfs_hash_and_remove(dir_sd, (*--attr)->name, NULL); + kernfs_remove_by_name(dir_sd, (*--attr)->name); } sysfs_put(dir_sd); @@ -292,7 +291,7 @@ void sysfs_unmerge_group(struct kobject *kobj, dir_sd = sysfs_get_dirent(kobj->sd, grp->name); if (dir_sd) { for (attr = grp->attrs; *attr; ++attr) - sysfs_hash_and_remove(dir_sd, (*attr)->name, NULL); + kernfs_remove_by_name(dir_sd, (*attr)->name); sysfs_put(dir_sd); } } @@ -335,7 +334,7 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, dir_sd = sysfs_get_dirent(kobj->sd, group_name); if (dir_sd) { - sysfs_hash_and_remove(dir_sd, link_name, NULL); + kernfs_remove_by_name(dir_sd, link_name); sysfs_put(dir_sd); } } diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index c660363fdaea..71583fc8100a 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -153,7 +153,7 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, if (targ->sd && (kobj->sd->s_flags & SYSFS_FLAG_NS)) ns = targ->sd->s_ns; spin_unlock(&sysfs_symlink_target_lock); - sysfs_hash_and_remove(kobj->sd, name, ns); + kernfs_remove_by_name_ns(kobj->sd, name, ns); } /** @@ -170,7 +170,7 @@ void sysfs_remove_link(struct kobject *kobj, const char *name) else parent_sd = kobj->sd; - sysfs_hash_and_remove(parent_sd, name, NULL); + kernfs_remove_by_name(parent_sd, name); } EXPORT_SYMBOL_GPL(sysfs_remove_link); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index e116c21a27bf..97625b15ca03 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -173,9 +173,6 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, struct sysfs_dirent *parent_sd); int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, struct sysfs_dirent *parent_sd); -void sysfs_remove(struct sysfs_dirent *sd); -int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name, - const void *ns); void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 254b9e872b09..83e151ad0619 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -7,6 +7,30 @@ #ifndef __LINUX_KERNFS_H #define __LINUX_KERNFS_H +#include + struct sysfs_dirent; +#ifdef CONFIG_SYSFS + +void kernfs_remove(struct sysfs_dirent *sd); +int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, + const void *ns); + +#else /* CONFIG_SYSFS */ + +static inline void kernfs_remove(struct sysfs_dirent *sd) { } + +static inline int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, + const char *name, const void *ns) +{ return -ENOSYS; } + +#endif /* CONFIG_SYSFS */ + +static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, + const char *name) +{ + return kernfs_remove_by_name_ns(parent, name, NULL); +} + #endif /* __LINUX_KERNFS_H */ -- cgit v1.2.3-59-g8ed1b From 5d0e26bb59a680a5d97db5b6629941603e8de229 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 23 Nov 2013 17:21:50 -0500 Subject: sysfs, kernfs: introduce kernfs_create_link() Separate out kernfs symlink interface - kernfs_create_link() - which takes and returns sysfs_dirents, from sysfs_do_create_link_sd(). sysfs_do_create_link_sd() now just determines the parent and target sysfs_dirents and invokes the new interface and handles dup warning. This patch doesn't introduce behavior changes. v2: Dummy implementation for !CONFIG_SYSFS updated to return -ENOSYS. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/symlink.c | 76 ++++++++++++++++++++++++++++++-------------------- include/linux/kernfs.h | 9 ++++++ 2 files changed, 55 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 71583fc8100a..41138e91947a 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -21,14 +21,48 @@ #include "sysfs.h" +/** + * kernfs_create_link - create a symlink + * @parent: directory to create the symlink in + * @name: name of the symlink + * @target: target node for the symlink to point to + * + * Returns the created node on success, ERR_PTR() value on error. + */ +struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, + const char *name, + struct sysfs_dirent *target) +{ + struct sysfs_dirent *sd; + struct sysfs_addrm_cxt acxt; + int error; + + sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK); + if (!sd) + return ERR_PTR(-ENOMEM); + + if (parent->s_flags & SYSFS_FLAG_NS) + sd->s_ns = target->s_ns; + sd->s_symlink.target_sd = target; + sysfs_get(target); /* ref owned by symlink */ + + sysfs_addrm_start(&acxt); + error = __sysfs_add_one(&acxt, sd, parent); + sysfs_addrm_finish(&acxt); + + if (!error) + return sd; + + sysfs_put(sd); + return ERR_PTR(error); +} + + static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, struct kobject *target, const char *name, int warn) { - struct sysfs_dirent *target_sd = NULL; - struct sysfs_dirent *sd = NULL; - struct sysfs_addrm_cxt acxt; - int error; + struct sysfs_dirent *sd, *target_sd = NULL; BUG_ON(!name || !parent_sd); @@ -42,36 +76,18 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, target_sd = sysfs_get(target->sd); spin_unlock(&sysfs_symlink_target_lock); - error = -ENOENT; if (!target_sd) - goto out_put; + return -ENOENT; - error = -ENOMEM; - sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK); - if (!sd) - goto out_put; - - if (parent_sd->s_flags & SYSFS_FLAG_NS) - sd->s_ns = target_sd->s_ns; - sd->s_symlink.target_sd = target_sd; - target_sd = NULL; /* reference is now owned by the symlink */ - - sysfs_addrm_start(&acxt); - if (warn) - error = sysfs_add_one(&acxt, sd, parent_sd); - else - error = __sysfs_add_one(&acxt, sd, parent_sd); - sysfs_addrm_finish(&acxt); - - if (error) - goto out_put; + sd = kernfs_create_link(parent_sd, name, target_sd); + sysfs_put(target_sd); - return 0; + if (!IS_ERR(sd)) + return 0; - out_put: - sysfs_put(target_sd); - sysfs_put(sd); - return error; + if (warn && PTR_ERR(sd) == -EEXIST) + sysfs_warn_dup(parent_sd, name); + return PTR_ERR(sd); } /** diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 83e151ad0619..fe6290d41776 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -8,17 +8,26 @@ #define __LINUX_KERNFS_H #include +#include struct sysfs_dirent; #ifdef CONFIG_SYSFS +struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, + const char *name, + struct sysfs_dirent *target); void kernfs_remove(struct sysfs_dirent *sd); int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, const void *ns); #else /* CONFIG_SYSFS */ +static inline struct sysfs_dirent * +kernfs_create_link(struct sysfs_dirent *parent, const char *name, + struct sysfs_dirent *target) +{ return ERR_PTR(-ENOSYS); } + static inline void kernfs_remove(struct sysfs_dirent *sd) { } static inline int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, -- cgit v1.2.3-59-g8ed1b From 890ece160c6465b49c42975d529c3481d89da8f5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 23 Nov 2013 17:21:51 -0500 Subject: sysfs, kernfs: introduce kernfs_rename[_ns]() Introduce kernfs rename interface, krenfs_rename[_ns](). This is just rename of sysfs_rename(). No functional changes. Function comment is added to kernfs_rename_ns() and @new_parent_sd is renamed to @new_parent for consistency with other kernfs interfaces. v2: Dummy implementation for !CONFIG_SYSFS updated to return -ENOSYS. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 23 +++++++++++++++-------- fs/sysfs/symlink.c | 2 +- fs/sysfs/sysfs.h | 3 --- include/linux/kernfs.h | 7 +++++++ 4 files changed, 23 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index edbde4e6e5e0..5ba896630d04 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -932,20 +932,27 @@ void sysfs_remove_dir(struct kobject *kobj) } } -int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd, - const char *new_name, const void *new_ns) +/** + * kernfs_rename_ns - move and rename a kernfs_node + * @sd: target node + * @new_parent: new parent to put @sd under + * @new_name: new name + * @new_ns: new namespace tag + */ +int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, + const char *new_name, const void *new_ns) { int error; mutex_lock(&sysfs_mutex); error = 0; - if ((sd->s_parent == new_parent_sd) && (sd->s_ns == new_ns) && + if ((sd->s_parent == new_parent) && (sd->s_ns == new_ns) && (strcmp(sd->s_name, new_name) == 0)) goto out; /* nothing to rename */ error = -EEXIST; - if (sysfs_find_dirent(new_parent_sd, new_name, new_ns)) + if (sysfs_find_dirent(new_parent, new_name, new_ns)) goto out; /* rename sysfs_dirent */ @@ -963,11 +970,11 @@ int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd, * Move to the appropriate place in the appropriate directories rbtree. */ sysfs_unlink_sibling(sd); - sysfs_get(new_parent_sd); + sysfs_get(new_parent); sysfs_put(sd->s_parent); sd->s_ns = new_ns; sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); - sd->s_parent = new_parent_sd; + sd->s_parent = new_parent; sysfs_link_sibling(sd); error = 0; @@ -981,7 +988,7 @@ int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, { struct sysfs_dirent *parent_sd = kobj->sd->s_parent; - return sysfs_rename(kobj->sd, parent_sd, new_name, new_ns); + return kernfs_rename_ns(kobj->sd, parent_sd, new_name, new_ns); } int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, @@ -994,7 +1001,7 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root; - return sysfs_rename(sd, new_parent_sd, sd->s_name, new_ns); + return kernfs_rename_ns(sd, new_parent_sd, sd->s_name, new_ns); } /** diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 41138e91947a..0922c53bd757 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -226,7 +226,7 @@ int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, if (sd->s_symlink.target_sd->s_dir.kobj != targ) goto out; - result = sysfs_rename(sd, parent_sd, new, new_ns); + result = kernfs_rename_ns(sd, parent_sd, new, new_ns); out: sysfs_put(sd); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 97625b15ca03..8b3fc210b90d 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -185,9 +185,6 @@ void release_sysfs_dirent(struct sysfs_dirent *sd); int sysfs_create_subdir(struct kobject *kobj, const char *name, struct sysfs_dirent **p_sd); -int sysfs_rename(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent_sd, - const char *new_name, const void *new_ns); - static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) { if (sd) { diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index fe6290d41776..803d9600cf72 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -20,6 +20,8 @@ struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, void kernfs_remove(struct sysfs_dirent *sd); int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, const void *ns); +int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, + const char *new_name, const void *new_ns); #else /* CONFIG_SYSFS */ @@ -34,6 +36,11 @@ static inline int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, const void *ns) { return -ENOSYS; } +static inline int kernfs_rename_ns(struct sysfs_dirent *sd, + struct sysfs_dirent *new_parent, + const char *new_name, const void *new_ns) +{ return -ENOSYS; } + #endif /* CONFIG_SYSFS */ static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, -- cgit v1.2.3-59-g8ed1b From 5d60418e54751c856f5aecc308620fde9572e481 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Sat, 23 Nov 2013 17:21:52 -0500 Subject: sysfs, kernfs: introduce kernfs_setattr() Introduce kernfs setattr interface - kernfs_setattr(). sysfs_sd_setattr() is renamed to __kernfs_setattr() and kernfs_setattr() is a simple wrapper around it with sysfs_mutex locking. sysfs_chmod_file() is updated to get an explicit ref on kobj->sd and then invoke kernfs_setattr() so that it doesn't have to use internal interface. This patch doesn't introduce any behavior differences. v2: Dummy implementation for !CONFIG_SYSFS updated to return -ENOSYS. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 13 +++++-------- fs/sysfs/inode.c | 21 +++++++++++++++++++-- fs/sysfs/sysfs.h | 1 - include/linux/kernfs.h | 8 ++++++++ 4 files changed, 32 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 5664410136ba..564abd201afb 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -922,19 +922,16 @@ int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, struct iattr newattrs; int rc; - mutex_lock(&sysfs_mutex); - - rc = -ENOENT; - sd = sysfs_find_dirent(kobj->sd, attr->name, NULL); + sd = sysfs_get_dirent(kobj->sd, attr->name); if (!sd) - goto out; + return -ENOENT; newattrs.ia_mode = (mode & S_IALLUGO) | (sd->s_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE; - rc = sysfs_sd_setattr(sd, &newattrs); - out: - mutex_unlock(&sysfs_mutex); + rc = kernfs_setattr(sd, &newattrs); + + sysfs_put(sd); return rc; } EXPORT_SYMBOL_GPL(sysfs_chmod_file); diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 1750f790af3b..5f7e2afb3457 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -67,7 +67,7 @@ static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) return attrs; } -int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr) +static int __kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr) { struct sysfs_inode_attrs *sd_attrs; struct iattr *iattrs; @@ -102,6 +102,23 @@ int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr) return 0; } +/** + * kernfs_setattr - set iattr on a node + * @sd: target node + * @iattr: iattr to set + * + * Returns 0 on success, -errno on failure. + */ +int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr) +{ + int ret; + + mutex_lock(&sysfs_mutex); + ret = __kernfs_setattr(sd, iattr); + mutex_unlock(&sysfs_mutex); + return ret; +} + int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) { struct inode *inode = dentry->d_inode; @@ -116,7 +133,7 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) if (error) goto out; - error = sysfs_sd_setattr(sd, iattr); + error = __kernfs_setattr(sd, iattr); if (error) goto out; diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 8b3fc210b90d..2abccfdd932e 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -207,7 +207,6 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) */ struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd); void sysfs_evict_inode(struct inode *inode); -int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); int sysfs_permission(struct inode *inode, int mask); int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 803d9600cf72..8cb673875715 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -10,6 +10,9 @@ #include #include +struct file; +struct iattr; + struct sysfs_dirent; #ifdef CONFIG_SYSFS @@ -22,6 +25,7 @@ int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, const void *ns); int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, const char *new_name, const void *new_ns); +int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); #else /* CONFIG_SYSFS */ @@ -41,6 +45,10 @@ static inline int kernfs_rename_ns(struct sysfs_dirent *sd, const char *new_name, const void *new_ns) { return -ENOSYS; } +static inline int kernfs_setattr(struct sysfs_dirent *sd, + const struct iattr *iattr) +{ return -ENOSYS; } + #endif /* CONFIG_SYSFS */ static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, -- cgit v1.2.3-59-g8ed1b From b9f3cecaba592d4e98cd155c91b1414323ed51e8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 29 Nov 2013 10:42:58 -0500 Subject: cgroup: remove cftype->release() Now that pidlist files don't use cftype->release(), it doesn't have any user left. Remove it. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- include/linux/cgroup.h | 2 -- kernel/cgroup.c | 3 --- 2 files changed, 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 492fa01ec2d3..5207c28c2402 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -499,8 +499,6 @@ struct cftype { * kick type for multiplexing. */ int (*trigger)(struct cgroup_subsys_state *css, unsigned int event); - - int (*release)(struct inode *inode, struct file *file); }; /* diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 1e09ded0387a..b59e3453eae7 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2448,12 +2448,9 @@ static int cgroup_file_open(struct inode *inode, struct file *file) static int cgroup_file_release(struct inode *inode, struct file *file) { struct cfent *cfe = __d_cfe(file->f_dentry); - struct cftype *cft = __d_cft(file->f_dentry); struct cgroup_subsys_state *css = cfe->css; int ret = 0; - if (cft->release) - ret = cft->release(inode, file); if (css->ss) css_put(css); if (file->f_op == &cgroup_seqfile_operations) -- cgit v1.2.3-59-g8ed1b From afb2bc14e1c989cf0635bd04edb5ff55b8c1c7bd Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 29 Nov 2013 10:42:59 -0500 Subject: cgroup: don't guarantee cgroup.procs is sorted if sane_behavior For some reason, tasks and cgroup.procs guarantee that the result is sorted. This is the only reason this whole pidlist logic is necessary instead of just iterating through sorted member tasks. We can't do anything about the existing interface but at least ensure that such expectation doesn't exist for the new interface so that pidlist logic may be removed in the distant future. This patch scrambles the sort order if sane_behavior so that the output is usually not sorted in the new interface. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- include/linux/cgroup.h | 3 +++ kernel/cgroup.c | 51 +++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 49 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 5207c28c2402..50d8cc37498b 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -275,6 +275,9 @@ enum { * - "tasks" is removed. Everything should be at process * granularity. Use "cgroup.procs" instead. * + * - "cgroup.procs" is not sorted. pids will be unique unless they + * got recycled inbetween reads. + * * - "release_agent" and "notify_on_release" are removed. * Replacement notification mechanism will be implemented. * diff --git a/kernel/cgroup.c b/kernel/cgroup.c index a2458031d851..f9f5fe3526ac 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -3564,11 +3564,49 @@ after: return dest; } +/* + * The two pid files - task and cgroup.procs - guaranteed that the result + * is sorted, which forced this whole pidlist fiasco. As pid order is + * different per namespace, each namespace needs differently sorted list, + * making it impossible to use, for example, single rbtree of member tasks + * sorted by task pointer. As pidlists can be fairly large, allocating one + * per open file is dangerous, so cgroup had to implement shared pool of + * pidlists keyed by cgroup and namespace. + * + * All this extra complexity was caused by the original implementation + * committing to an entirely unnecessary property. In the long term, we + * want to do away with it. Explicitly scramble sort order if + * sane_behavior so that no such expectation exists in the new interface. + * + * Scrambling is done by swapping every two consecutive bits, which is + * non-identity one-to-one mapping which disturbs sort order sufficiently. + */ +static pid_t pid_fry(pid_t pid) +{ + unsigned a = pid & 0x55555555; + unsigned b = pid & 0xAAAAAAAA; + + return (a << 1) | (b >> 1); +} + +static pid_t cgroup_pid_fry(struct cgroup *cgrp, pid_t pid) +{ + if (cgroup_sane_behavior(cgrp)) + return pid_fry(pid); + else + return pid; +} + static int cmppid(const void *a, const void *b) { return *(pid_t *)a - *(pid_t *)b; } +static int fried_cmppid(const void *a, const void *b) +{ + return pid_fry(*(pid_t *)a) - pid_fry(*(pid_t *)b); +} + static struct cgroup_pidlist *cgroup_pidlist_find(struct cgroup *cgrp, enum cgroup_filetype type) { @@ -3656,7 +3694,10 @@ static int pidlist_array_load(struct cgroup *cgrp, enum cgroup_filetype type, css_task_iter_end(&it); length = n; /* now sort & (if procs) strip out duplicates */ - sort(array, length, sizeof(pid_t), cmppid, NULL); + if (cgroup_sane_behavior(cgrp)) + sort(array, length, sizeof(pid_t), fried_cmppid, NULL); + else + sort(array, length, sizeof(pid_t), cmppid, NULL); if (type == CGROUP_FILE_PROCS) length = pidlist_uniq(array, length); @@ -3777,10 +3818,10 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos) while (index < end) { int mid = (index + end) / 2; - if (l->list[mid] == pid) { + if (cgroup_pid_fry(cgrp, l->list[mid]) == pid) { index = mid; break; - } else if (l->list[mid] <= pid) + } else if (cgroup_pid_fry(cgrp, l->list[mid]) <= pid) index = mid + 1; else end = mid; @@ -3791,7 +3832,7 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos) return NULL; /* Update the abstract position to be the actual pid that we found */ iter = l->list + index; - *pos = *iter; + *pos = cgroup_pid_fry(cgrp, *iter); return iter; } @@ -3820,7 +3861,7 @@ static void *cgroup_pidlist_next(struct seq_file *s, void *v, loff_t *pos) if (p >= end) { return NULL; } else { - *pos = *p; + *pos = cgroup_pid_fry(of->cgrp, *p); return p; } } -- cgit v1.2.3-59-g8ed1b From 93b2b8e4aa4317e3fe6414d117deb5f3c362e8bb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:15 -0500 Subject: sysfs, kernfs: introduce kernfs_create_dir[_ns]() Introduce kernfs interface to manipulate a directory which takes and returns sysfs_dirents. create_dir() is renamed to kernfs_create_dir_ns() and its argumantes and return value are updated. create_dir() usages are replaced with kernfs_create_dir_ns() and sysfs_create_subdir() usages are replaced with kernfs_create_dir(). Dup warnings are handled explicitly by sysfs users of the kernfs interface. sysfs_enable_ns() is renamed to kernfs_enable_ns(). This patch doesn't introduce any behavior changes. v2: Dummy implementation for !CONFIG_SYSFS updated to return -ENOSYS. v3: kernfs_enable_ns() added. v4: Refreshed on top of "sysfs: drop kobj_ns_type handling, take #2" so that this patch removes sysfs_enable_ns(). Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 54 ++++++++++++++++++++++++++++---------------------- fs/sysfs/group.c | 9 ++++++--- fs/sysfs/sysfs.h | 3 --- include/linux/kernfs.h | 17 ++++++++++++++++ include/linux/sysfs.h | 6 ------ lib/kobject.c | 2 +- 6 files changed, 54 insertions(+), 37 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index aeb08bd3f3dd..cfbf4091fe5c 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -666,9 +666,18 @@ struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, } EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns); -static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, - const char *name, const void *ns, - struct sysfs_dirent **p_sd) +/** + * kernfs_create_dir_ns - create a directory + * @parent: parent in which to create a new directory + * @name: name of the new directory + * @priv: opaque data associated with the new directory + * @ns: optional namespace tag of the directory + * + * Returns the created node on success, ERR_PTR() value on failure. + */ +struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, + const char *name, void *priv, + const void *ns) { umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; struct sysfs_addrm_cxt acxt; @@ -678,28 +687,21 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, /* allocate */ sd = sysfs_new_dirent(name, mode, SYSFS_DIR); if (!sd) - return -ENOMEM; + return ERR_PTR(-ENOMEM); sd->s_ns = ns; - sd->priv = kobj; + sd->priv = priv; /* link in */ sysfs_addrm_start(&acxt); - rc = sysfs_add_one(&acxt, sd, parent_sd); + rc = __sysfs_add_one(&acxt, sd, parent); sysfs_addrm_finish(&acxt); - if (rc == 0) - *p_sd = sd; - else - sysfs_put(sd); + if (!rc) + return sd; - return rc; -} - -int sysfs_create_subdir(struct kobject *kobj, const char *name, - struct sysfs_dirent **p_sd) -{ - return create_dir(kobj, kobj->sd, name, NULL, p_sd); + sysfs_put(sd); + return ERR_PTR(rc); } /** @@ -710,7 +712,6 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name, int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) { struct sysfs_dirent *parent_sd, *sd; - int error = 0; BUG_ON(!kobj); @@ -722,10 +723,15 @@ int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) if (!parent_sd) return -ENOENT; - error = create_dir(kobj, parent_sd, kobject_name(kobj), ns, &sd); - if (!error) - kobj->sd = sd; - return error; + sd = kernfs_create_dir_ns(parent_sd, kobject_name(kobj), kobj, ns); + if (IS_ERR(sd)) { + if (PTR_ERR(sd) == -EEXIST) + sysfs_warn_dup(parent_sd, kobject_name(kobj)); + return PTR_ERR(sd); + } + + kobj->sd = sd; + return 0; } static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry, @@ -1005,14 +1011,14 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, } /** - * sysfs_enable_ns - enable namespace under a directory + * kernfs_enable_ns - enable namespace under a directory * @sd: directory of interest, should be empty * * This is to be called right after @sd is created to enable namespace * under it. All children of @sd must have non-NULL namespace tags and * only the ones which match the super_block's tag will be visible. */ -void sysfs_enable_ns(struct sysfs_dirent *sd) +void kernfs_enable_ns(struct sysfs_dirent *sd) { WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); WARN_ON_ONCE(!RB_EMPTY_ROOT(&sd->s_dir.children)); diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 4bd997340830..065689ddb4cb 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -101,9 +101,12 @@ static int internal_create_group(struct kobject *kobj, int update, return -EINVAL; } if (grp->name) { - error = sysfs_create_subdir(kobj, grp->name, &sd); - if (error) - return error; + sd = kernfs_create_dir(kobj->sd, grp->name, kobj); + if (IS_ERR(sd)) { + if (PTR_ERR(sd) == -EEXIST) + sysfs_warn_dup(kobj->sd, grp->name); + return PTR_ERR(sd); + } } else sd = kobj->sd; sysfs_get(sd); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index a6f3fa3f02fe..9ac234ef4943 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -179,9 +179,6 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type); void release_sysfs_dirent(struct sysfs_dirent *sd); -int sysfs_create_subdir(struct kobject *kobj, const char *name, - struct sysfs_dirent **p_sd); - static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) { if (sd) { diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 8cb673875715..e8b73d4a08d2 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -17,6 +17,9 @@ struct sysfs_dirent; #ifdef CONFIG_SYSFS +struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, + const char *name, void *priv, + const void *ns); struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, const char *name, struct sysfs_dirent *target); @@ -25,10 +28,16 @@ int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, const void *ns); int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, const char *new_name, const void *new_ns); +void kernfs_enable_ns(struct sysfs_dirent *sd); int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); #else /* CONFIG_SYSFS */ +static inline struct sysfs_dirent * +kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, + const void *ns) +{ return ERR_PTR(-ENOSYS); } + static inline struct sysfs_dirent * kernfs_create_link(struct sysfs_dirent *parent, const char *name, struct sysfs_dirent *target) @@ -45,12 +54,20 @@ static inline int kernfs_rename_ns(struct sysfs_dirent *sd, const char *new_name, const void *new_ns) { return -ENOSYS; } +static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { } + static inline int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr) { return -ENOSYS; } #endif /* CONFIG_SYSFS */ +static inline struct sysfs_dirent * +kernfs_create_dir(struct sysfs_dirent *parent, const char *name, void *priv) +{ + return kernfs_create_dir_ns(parent, name, priv, NULL); +} + static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, const char *name) { diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index e17381a92e1a..2bc735d3e938 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -219,8 +219,6 @@ int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *target, void sysfs_delete_link(struct kobject *dir, struct kobject *targ, const char *name); -void sysfs_enable_ns(struct sysfs_dirent *sd); - int __must_check sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp); int __must_check sysfs_create_groups(struct kobject *kobj, @@ -354,10 +352,6 @@ static inline void sysfs_delete_link(struct kobject *k, struct kobject *t, { } -static inline void sysfs_enable_ns(struct sysfs_dirent *sd) -{ -} - static inline int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp) { diff --git a/lib/kobject.c b/lib/kobject.c index 16e9335b32d3..b8d848fb1377 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -94,7 +94,7 @@ static int create_dir(struct kobject *kobj) BUG_ON(ops->type >= KOBJ_NS_TYPES); BUG_ON(!kobj_ns_type_registered(ops->type)); - sysfs_enable_ns(kobj->sd); + kernfs_enable_ns(kobj->sd); } return 0; -- cgit v1.2.3-59-g8ed1b From dd8a5b036b6e8d50854e130555f90f062c5eacec Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:20 -0500 Subject: sysfs, kernfs: move sysfs_open_file to include/linux/kernfs.h sysfs_open_file will be used as the primary handle for kernfs methods. Move its definition from fs/sysfs/file.c to include/linux/kernfs.h and mark the public and private fields. This is pure relocation. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 11 ----------- include/linux/kernfs.h | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index a43df04c81f9..acba5835577e 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -47,17 +47,6 @@ struct sysfs_open_dirent { struct list_head files; /* goes through sysfs_open_file.list */ }; -struct sysfs_open_file { - struct sysfs_dirent *sd; - struct file *file; - struct mutex mutex; - int event; - struct list_head list; - - bool mmapped; - const struct vm_operations_struct *vm_ops; -}; - static bool sysfs_is_bin(struct sysfs_dirent *sd) { return sysfs_type(sd) == SYSFS_KOBJ_BIN_ATTR; diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index e8b73d4a08d2..b923052c29d0 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -9,12 +9,30 @@ #include #include +#include +#include struct file; struct iattr; +struct seq_file; +struct vm_area_struct; struct sysfs_dirent; +struct sysfs_open_file { + /* published fields */ + struct sysfs_dirent *sd; + struct file *file; + + /* private fields, do not use outside kernfs proper */ + struct mutex mutex; + int event; + struct list_head list; + + bool mmapped; + const struct vm_operations_struct *vm_ops; +}; + #ifdef CONFIG_SYSFS struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, -- cgit v1.2.3-59-g8ed1b From f6acf8bb6a40ba3bfcf542e4c4c9e8968c8cb57a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:21 -0500 Subject: sysfs, kernfs: introduce kernfs_ops We're in the process of separating out core sysfs functionality into kernfs which will deal with sysfs_dirents directly. This patch introduces kernfs_ops which hosts methods kernfs users implement and updates fs/sysfs/file.c such that sysfs_kf_*() functions populate kernfs_ops and kernfs_file_*() functions call the matching entries from kernfs_ops. kernfs_ops contains the following groups of methods. * seq_show() - for kernfs files which use seq_file for reads. * read() - for direct read implementations. Used iff seq_show() is not implemented. * write() - for writes. * mmap() - for mmaps. Notes: * sysfs_elem_attr->ops is added so that kernfs_ops can be accessed from sysfs_dirent. kernfs_ops() helper is added to verify locking and access the field. * SYSFS_FLAG_HAS_(SEQ_SHOW|MMAP) added. sd->s_attr->ops is accessible only while holding active_ref and there are cases where we want to take different actions depending on which ops are implemented. These two flags cache whether the two ops are implemented for those. * kernfs_file_*() no longer test sysfs type but chooses different behaviors depending on which methods in kernfs_ops are implemented. The conversions are trivial except for the open path. As kernfs_file_open() now decides whether to allow read/write accesses depending on the kernfs_ops implemented, the presence of methods in kobjs and attribute_bin should be propagated to kernfs_ops. sysfs_add_file_mode_ns() is updated so that it propagates presence / absence of the callbacks through _empty, _ro, _wo, _rw kernfs_ops. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 146 +++++++++++++++++++++++++++++++++++++------------ fs/sysfs/sysfs.h | 3 + include/linux/kernfs.h | 26 +++++++++ 3 files changed, 141 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index acba5835577e..cbebc335af8c 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -57,6 +57,17 @@ static struct sysfs_open_file *sysfs_of(struct file *file) return ((struct seq_file *)file->private_data)->private; } +/* + * Determine the kernfs_ops for the given sysfs_dirent. This function must + * be called while holding an active reference. + */ +static const struct kernfs_ops *kernfs_ops(struct sysfs_dirent *sd) +{ + if (!sysfs_ignore_lockdep(sd)) + lockdep_assert_held(sd); + return sd->s_attr.ops; +} + /* * Determine ktype->sysfs_ops for the given sysfs_dirent. This function * must be called while holding an active reference. @@ -180,7 +191,7 @@ static int kernfs_seq_show(struct seq_file *sf, void *v) of->event = atomic_read(&of->sd->s_attr.open->event); - return sysfs_kf_seq_show(sf, v); + return of->sd->s_attr.ops->seq_show(sf, v); } static const struct seq_operations kernfs_seq_ops = { @@ -201,6 +212,7 @@ static ssize_t kernfs_file_direct_read(struct sysfs_open_file *of, loff_t *ppos) { ssize_t len = min_t(size_t, count, PAGE_SIZE); + const struct kernfs_ops *ops; char *buf; buf = kmalloc(len, GFP_KERNEL); @@ -218,7 +230,11 @@ static ssize_t kernfs_file_direct_read(struct sysfs_open_file *of, goto out_free; } - len = sysfs_kf_bin_read(of, buf, len, *ppos); + ops = kernfs_ops(of->sd); + if (ops->read) + len = ops->read(of, buf, len, *ppos); + else + len = -EINVAL; sysfs_put_active(of->sd); mutex_unlock(&of->mutex); @@ -250,10 +266,10 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, { struct sysfs_open_file *of = sysfs_of(file); - if (sysfs_is_bin(of->sd)) - return kernfs_file_direct_read(of, user_buf, count, ppos); - else + if (of->sd->s_flags & SYSFS_FLAG_HAS_SEQ_SHOW) return seq_read(file, user_buf, count, ppos); + else + return kernfs_file_direct_read(of, user_buf, count, ppos); } /* kernfs write callback for regular sysfs files */ @@ -312,6 +328,7 @@ static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf, { struct sysfs_open_file *of = sysfs_of(file); ssize_t len = min_t(size_t, count, PAGE_SIZE); + const struct kernfs_ops *ops; char *buf; buf = kmalloc(len + 1, GFP_KERNEL); @@ -335,10 +352,11 @@ static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf, goto out_free; } - if (sysfs_is_bin(of->sd)) - len = sysfs_kf_bin_write(of, buf, len, *ppos); + ops = kernfs_ops(of->sd); + if (ops->write) + len = ops->write(of, buf, len, *ppos); else - len = sysfs_kf_write(of, buf, len, *ppos); + len = -EINVAL; sysfs_put_active(of->sd); mutex_unlock(&of->mutex); @@ -524,6 +542,7 @@ static const struct vm_operations_struct kernfs_vm_ops = { static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) { struct sysfs_open_file *of = sysfs_of(file); + const struct kernfs_ops *ops; int rc; mutex_lock(&of->mutex); @@ -532,8 +551,9 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) if (!sysfs_get_active(of->sd)) goto out_unlock; - if (sysfs_is_bin(of->sd)) - rc = sysfs_kf_bin_mmap(of, vma); + ops = kernfs_ops(of->sd); + if (ops->mmap) + rc = ops->mmap(of, vma); if (rc) goto out_put; @@ -660,34 +680,19 @@ static void sysfs_put_open_dirent(struct sysfs_dirent *sd, static int kernfs_file_open(struct inode *inode, struct file *file) { struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; - struct kobject *kobj = attr_sd->s_parent->priv; + const struct kernfs_ops *ops; struct sysfs_open_file *of; bool has_read, has_write, has_mmap; int error = -EACCES; - /* need attr_sd for attr and ops, its parent for kobj */ if (!sysfs_get_active(attr_sd)) return -ENODEV; - if (sysfs_is_bin(attr_sd)) { - struct bin_attribute *battr = attr_sd->priv; + ops = kernfs_ops(attr_sd); - has_read = battr->read || battr->mmap; - has_write = battr->write || battr->mmap; - has_mmap = battr->mmap; - } else { - const struct sysfs_ops *ops = sysfs_file_ops(attr_sd); - - /* every kobject with an attribute needs a ktype assigned */ - if (WARN(!ops, KERN_ERR - "missing sysfs attribute operations for kobject: %s\n", - kobject_name(kobj))) - goto err_out; - - has_read = ops->show; - has_write = ops->store; - has_mmap = false; - } + has_read = ops->seq_show || ops->read || ops->mmap; + has_write = ops->write || ops->mmap; + has_mmap = ops->mmap; /* check perms and supported operations */ if ((file->f_mode & FMODE_WRITE) && @@ -729,10 +734,10 @@ static int kernfs_file_open(struct inode *inode, struct file *file) * seq_file or is not requested. This unifies private data access * and readable regular files are the vast majority anyway. */ - if (sysfs_is_bin(attr_sd)) - error = seq_open(file, NULL); - else + if (ops->seq_show) error = seq_open(file, &kernfs_seq_ops); + else + error = seq_open(file, NULL); if (error) goto err_free; @@ -777,7 +782,7 @@ void sysfs_unmap_bin_file(struct sysfs_dirent *sd) struct sysfs_open_dirent *od; struct sysfs_open_file *of; - if (!sysfs_is_bin(sd)) + if (!(sd->s_flags & SYSFS_FLAG_HAS_MMAP)) return; spin_lock_irq(&sysfs_open_dirent_lock); @@ -880,23 +885,96 @@ const struct file_operations kernfs_file_operations = { .poll = kernfs_file_poll, }; +static const struct kernfs_ops sysfs_file_kfops_empty = { +}; + +static const struct kernfs_ops sysfs_file_kfops_ro = { + .seq_show = sysfs_kf_seq_show, +}; + +static const struct kernfs_ops sysfs_file_kfops_wo = { + .write = sysfs_kf_write, +}; + +static const struct kernfs_ops sysfs_file_kfops_rw = { + .seq_show = sysfs_kf_seq_show, + .write = sysfs_kf_write, +}; + +static const struct kernfs_ops sysfs_bin_kfops_ro = { + .read = sysfs_kf_bin_read, +}; + +static const struct kernfs_ops sysfs_bin_kfops_wo = { + .write = sysfs_kf_bin_write, +}; + +static const struct kernfs_ops sysfs_bin_kfops_rw = { + .read = sysfs_kf_bin_read, + .write = sysfs_kf_bin_write, + .mmap = sysfs_kf_bin_mmap, +}; + int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, const struct attribute *attr, int type, umode_t amode, const void *ns) { umode_t mode = (amode & S_IALLUGO) | S_IFREG; + const struct kernfs_ops *ops; struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; int rc; + if (type == SYSFS_KOBJ_ATTR) { + struct kobject *kobj = dir_sd->priv; + const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops; + + /* every kobject with an attribute needs a ktype assigned */ + if (WARN(!sysfs_ops, KERN_ERR + "missing sysfs attribute operations for kobject: %s\n", + kobject_name(kobj))) + return -EINVAL; + + if (sysfs_ops->show && sysfs_ops->store) + ops = &sysfs_file_kfops_rw; + else if (sysfs_ops->show) + ops = &sysfs_file_kfops_ro; + else if (sysfs_ops->store) + ops = &sysfs_file_kfops_wo; + else + ops = &sysfs_file_kfops_empty; + } else { + struct bin_attribute *battr = (void *)attr; + + if ((battr->read && battr->write) || battr->mmap) + ops = &sysfs_bin_kfops_rw; + else if (battr->read) + ops = &sysfs_bin_kfops_ro; + else if (battr->write) + ops = &sysfs_bin_kfops_wo; + else + ops = &sysfs_file_kfops_empty; + } + sd = sysfs_new_dirent(attr->name, mode, type); if (!sd) return -ENOMEM; + sd->s_attr.ops = ops; sd->s_ns = ns; sd->priv = (void *)attr; sysfs_dirent_init_lockdep(sd); + /* + * sd->s_attr.ops is accesible only while holding active ref. We + * need to know whether some ops are implemented outside active + * ref. Cache their existence in flags. + */ + if (ops->seq_show) + sd->s_flags |= SYSFS_FLAG_HAS_SEQ_SHOW; + if (ops->mmap) + sd->s_flags |= SYSFS_FLAG_HAS_MMAP; + sysfs_addrm_start(&acxt); rc = sysfs_add_one(&acxt, sd, dir_sd); sysfs_addrm_finish(&acxt); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 619250d2d7c1..c05e0ddd0268 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -27,6 +27,7 @@ struct sysfs_elem_symlink { }; struct sysfs_elem_attr { + const struct kernfs_ops *ops; struct sysfs_open_dirent *open; }; @@ -89,6 +90,8 @@ struct sysfs_dirent { #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK #define SYSFS_FLAG_NS 0x01000 #define SYSFS_FLAG_REMOVED 0x02000 +#define SYSFS_FLAG_HAS_SEQ_SHOW 0x04000 +#define SYSFS_FLAG_HAS_MMAP 0x08000 static inline unsigned int sysfs_type(struct sysfs_dirent *sd) { diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index b923052c29d0..97c6c0f91325 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -33,6 +33,32 @@ struct sysfs_open_file { const struct vm_operations_struct *vm_ops; }; +struct kernfs_ops { + /* + * Read is handled by either seq_file or raw_read(). + * + * If seq_show() is present, seq_file path is active. The behavior + * is equivalent to single_open(). @sf->private points to the + * associated sysfs_open_file. + * + * read() is bounced through kernel buffer and a read larger than + * PAGE_SIZE results in partial operation of PAGE_SIZE. + */ + int (*seq_show)(struct seq_file *sf, void *v); + + ssize_t (*read)(struct sysfs_open_file *of, char *buf, size_t bytes, + loff_t off); + + /* + * write() is bounced through kernel buffer and a write larger than + * PAGE_SIZE results in partial operation of PAGE_SIZE. + */ + ssize_t (*write)(struct sysfs_open_file *of, char *buf, size_t bytes, + loff_t off); + + int (*mmap)(struct sysfs_open_file *of, struct vm_area_struct *vma); +}; + #ifdef CONFIG_SYSFS struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, -- cgit v1.2.3-59-g8ed1b From 496f73944a4a974f89d48920bf368aec8841b195 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:24 -0500 Subject: sysfs, kernfs: introduce kernfs_create_file[_ns]() Introduce kernfs interface to create a file which takes and returns sysfs_dirents. The actual file creation part is separated out from sysfs_add_file_mode_ns() into kernfs_create_file_ns(). The former now only decides the kernfs_ops to use and the file's size and invokes the latter. This patch doesn't introduce behavior changes. v2: Dummy implementation for !CONFIG_SYSFS updated to return -ENOSYS. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 53 +++++++++++++++++++++++++++++++++++++++----------- include/linux/kernfs.h | 18 +++++++++++++++++ 2 files changed, 60 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index e2ce6743113a..69cca0f4ccf3 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -912,14 +912,11 @@ static const struct kernfs_ops sysfs_bin_kfops_rw = { int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, const struct attribute *attr, bool is_bin, - umode_t amode, const void *ns) + umode_t mode, const void *ns) { - umode_t mode = (amode & S_IALLUGO) | S_IFREG; const struct kernfs_ops *ops; - struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; loff_t size; - int rc; if (!is_bin) { struct kobject *kobj = dir_sd->priv; @@ -956,14 +953,47 @@ int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, size = battr->size; } - sd = sysfs_new_dirent(attr->name, mode, SYSFS_KOBJ_ATTR); + sd = kernfs_create_file_ns(dir_sd, attr->name, mode, size, + ops, (void *)attr, ns); + if (IS_ERR(sd)) { + if (PTR_ERR(sd) == -EEXIST) + sysfs_warn_dup(dir_sd, attr->name); + return PTR_ERR(sd); + } + return 0; +} + +/** + * kernfs_create_file_ns - create a file + * @parent: directory to create the file in + * @name: name of the file + * @mode: mode of the file + * @size: size of the file + * @ops: kernfs operations for the file + * @priv: private data for the file + * @ns: optional namespace tag of the file + * + * Returns the created node on success, ERR_PTR() value on error. + */ +struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns) +{ + struct sysfs_addrm_cxt acxt; + struct sysfs_dirent *sd; + int rc; + + sd = sysfs_new_dirent(name, (mode & S_IALLUGO) | S_IFREG, + SYSFS_KOBJ_ATTR); if (!sd) - return -ENOMEM; + return ERR_PTR(-ENOMEM); sd->s_attr.ops = ops; sd->s_attr.size = size; sd->s_ns = ns; - sd->priv = (void *)attr; + sd->priv = priv; sysfs_dirent_init_lockdep(sd); /* @@ -977,13 +1007,14 @@ int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, sd->s_flags |= SYSFS_FLAG_HAS_MMAP; sysfs_addrm_start(&acxt); - rc = sysfs_add_one(&acxt, sd, dir_sd); + rc = __sysfs_add_one(&acxt, sd, parent); sysfs_addrm_finish(&acxt); - if (rc) + if (rc) { sysfs_put(sd); - - return rc; + return ERR_PTR(rc); + } + return sd; } int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 97c6c0f91325..d0912cf02087 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -64,6 +64,11 @@ struct kernfs_ops { struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns); +struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns); struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, const char *name, struct sysfs_dirent *target); @@ -82,6 +87,12 @@ kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns) { return ERR_PTR(-ENOSYS); } +static inline struct sysfs_dirent * +kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name, + umode_t mode, loff_t size, const struct kernfs_ops *ops, + void *priv, const void *ns) +{ return ERR_PTR(-ENOSYS); } + static inline struct sysfs_dirent * kernfs_create_link(struct sysfs_dirent *parent, const char *name, struct sysfs_dirent *target) @@ -112,6 +123,13 @@ kernfs_create_dir(struct sysfs_dirent *parent, const char *name, void *priv) return kernfs_create_dir_ns(parent, name, priv, NULL); } +static inline struct sysfs_dirent * +kernfs_create_file(struct sysfs_dirent *parent, const char *name, umode_t mode, + loff_t size, const struct kernfs_ops *ops, void *priv) +{ + return kernfs_create_file_ns(parent, name, mode, size, ops, priv, NULL); +} + static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, const char *name) { -- cgit v1.2.3-59-g8ed1b From d19b9846df64d8845be682b6318bd1aee246cf60 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:26 -0500 Subject: sysfs, kernfs: add kernfs_ops->seq_{start|next|stop}() kernfs_ops currently only supports single_open() behavior which is pretty restrictive. Add optional callbacks ->seq_{start|next|stop}() which, when implemented, are invoked for seq_file traversal. This allows full seq_file functionality for kernfs users. This currently doesn't have any user and doesn't change any behavior. v2: Refreshed on top of the updated "sysfs, kernfs: prepare read path for kernfs". Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 39 ++++++++++++++++++++++++++++----------- include/linux/kernfs.h | 9 +++++++-- 2 files changed, 35 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 9852450867cf..74e3478d9cb4 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -146,6 +146,7 @@ static ssize_t sysfs_kf_bin_read(struct sysfs_open_file *of, char *buf, static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) { struct sysfs_open_file *of = sf->private; + const struct kernfs_ops *ops; /* * @of->mutex nests outside active ref and is just to ensure that @@ -155,26 +156,42 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) if (!sysfs_get_active(of->sd)) return ERR_PTR(-ENODEV); - /* - * The same behavior and code as single_open(). Returns !NULL if - * pos is at the beginning; otherwise, NULL. - */ - return NULL + !*ppos; + ops = kernfs_ops(of->sd); + if (ops->seq_start) { + return ops->seq_start(sf, ppos); + } else { + /* + * The same behavior and code as single_open(). Returns + * !NULL if pos is at the beginning; otherwise, NULL. + */ + return NULL + !*ppos; + } } static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) { - /* - * The same behavior and code as single_open(), always terminate - * after the initial read. - */ - ++*ppos; - return NULL; + struct sysfs_open_file *of = sf->private; + const struct kernfs_ops *ops = kernfs_ops(of->sd); + + if (ops->seq_next) { + return ops->seq_next(sf, v, ppos); + } else { + /* + * The same behavior and code as single_open(), always + * terminate after the initial read. + */ + ++*ppos; + return NULL; + } } static void kernfs_seq_stop(struct seq_file *sf, void *v) { struct sysfs_open_file *of = sf->private; + const struct kernfs_ops *ops = kernfs_ops(of->sd); + + if (ops->seq_stop) + ops->seq_stop(sf, v); sysfs_put_active(of->sd); mutex_unlock(&of->mutex); diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index d0912cf02087..ba993ebcd81e 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -37,8 +37,9 @@ struct kernfs_ops { /* * Read is handled by either seq_file or raw_read(). * - * If seq_show() is present, seq_file path is active. The behavior - * is equivalent to single_open(). @sf->private points to the + * If seq_show() is present, seq_file path is active. Other seq + * operations are optional and if not implemented, the behavior is + * equivalent to single_open(). @sf->private points to the * associated sysfs_open_file. * * read() is bounced through kernel buffer and a read larger than @@ -46,6 +47,10 @@ struct kernfs_ops { */ int (*seq_show)(struct seq_file *sf, void *v); + void *(*seq_start)(struct seq_file *sf, loff_t *ppos); + void *(*seq_next)(struct seq_file *sf, void *v, loff_t *ppos); + void (*seq_stop)(struct seq_file *sf, void *v); + ssize_t (*read)(struct sysfs_open_file *of, char *buf, size_t bytes, loff_t off); -- cgit v1.2.3-59-g8ed1b From 024f647117d697165aaadf3f1af1343b7000149a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:27 -0500 Subject: sysfs, kernfs: introduce kernfs_notify() Introduce kernfs interface to wake up poll(2) which takes and returns sysfs_dirents. sysfs_notify_dirent() is renamed to kernfs_notify() and sysfs_notify() is updated so that it doesn't directly grab sysfs_mutex but acquires the target sysfs_dirents using sysfs_get_dirent(). sysfs_notify_dirent() is reimplemented as a dumb inline wrapper around kernfs_notify(). This patch doesn't introduce any behavior changes. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/file.c | 33 ++++++++++++++++++++++----------- include/linux/kernfs.h | 3 +++ include/linux/sysfs.h | 9 +++++---- 3 files changed, 30 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 74e3478d9cb4..a68cbef3a674 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -851,7 +851,13 @@ static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) return DEFAULT_POLLMASK|POLLERR|POLLPRI; } -void sysfs_notify_dirent(struct sysfs_dirent *sd) +/** + * kernfs_notify - notify a kernfs file + * @sd: file to notify + * + * Notify @sd such that poll(2) on @sd wakes up. + */ +void kernfs_notify(struct sysfs_dirent *sd) { struct sysfs_open_dirent *od; unsigned long flags; @@ -868,22 +874,27 @@ void sysfs_notify_dirent(struct sysfs_dirent *sd) spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags); } -EXPORT_SYMBOL_GPL(sysfs_notify_dirent); +EXPORT_SYMBOL_GPL(kernfs_notify); void sysfs_notify(struct kobject *k, const char *dir, const char *attr) { - struct sysfs_dirent *sd = k->sd; - - mutex_lock(&sysfs_mutex); + struct sysfs_dirent *sd = k->sd, *tmp; if (sd && dir) - sd = sysfs_find_dirent(sd, dir, NULL); - if (sd && attr) - sd = sysfs_find_dirent(sd, attr, NULL); - if (sd) - sysfs_notify_dirent(sd); + sd = sysfs_get_dirent(sd, dir); + else + sysfs_get(sd); - mutex_unlock(&sysfs_mutex); + if (sd && attr) { + tmp = sysfs_get_dirent(sd, attr); + sysfs_put(sd); + sd = tmp; + } + + if (sd) { + kernfs_notify(sd); + sysfs_put(sd); + } } EXPORT_SYMBOL_GPL(sysfs_notify); diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index ba993ebcd81e..f20796ecc76e 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -84,6 +84,7 @@ int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, const char *new_name, const void *new_ns); void kernfs_enable_ns(struct sysfs_dirent *sd); int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); +void kernfs_notify(struct sysfs_dirent *sd); #else /* CONFIG_SYSFS */ @@ -120,6 +121,8 @@ static inline int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr) { return -ENOSYS; } +static inline void kernfs_notify(struct sysfs_dirent *sd) { } + #endif /* CONFIG_SYSFS */ static inline struct sysfs_dirent * diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 2bc735d3e938..0ab2b023b613 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -243,7 +243,6 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, const char *link_name); void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr); -void sysfs_notify_dirent(struct sysfs_dirent *sd); struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, const unsigned char *name, const void *ns); @@ -418,9 +417,6 @@ static inline void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr) { } -static inline void sysfs_notify_dirent(struct sysfs_dirent *sd) -{ -} static inline struct sysfs_dirent * sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, const unsigned char *name, const void *ns) @@ -466,4 +462,9 @@ sysfs_get_dirent(struct sysfs_dirent *parent_sd, const unsigned char *name) return sysfs_get_dirent_ns(parent_sd, name, NULL); } +static inline void sysfs_notify_dirent(struct sysfs_dirent *sd) +{ + kernfs_notify(sd); +} + #endif /* _SYSFS_H_ */ -- cgit v1.2.3-59-g8ed1b From 517e64f57883bd63c5a4ab8b3d0d3ed68c55d0cf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:29 -0500 Subject: sysfs, kernfs: revamp sysfs_dirent active_ref lockdep annotation Currently, sysfs_dirent active_ref lockdep annotation uses attribute->[s]key as the lockdep key, which forces kernfs_create_file_ns() to assume that sysfs_dirent->priv is pointing to a struct attribute which may not be true for non-sysfs users. This patch restructures the lockdep annotation such that * kernfs_ops contains lockdep_key which is used by default for files created kernfs_create_file_ns(). * kernfs_create_file_ns_key() is introduced which takes an extra @key argument. The created file will use the specified key for active_ref lockdep annotation. If NULL is specified, lockdep for the file is disabled. * sysfs_add_file_mode_ns() is updated to use kernfs_create_file_ns_key() with the appropriate key from the attribute or NULL if ignore_lockdep is set. This makes the lockdep annotation properly contained in kernfs while allowing sysfs to cleanly keep its current behavior. This patch doesn't introduce any behavior differences. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 4 ++-- fs/sysfs/file.c | 35 ++++++++++++++++++++++++----------- fs/sysfs/sysfs.h | 32 +------------------------------- include/linux/kernfs.h | 37 +++++++++++++++++++++++++++++-------- 4 files changed, 56 insertions(+), 52 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index e88e9a94a083..8f2d577b5f64 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -150,7 +150,7 @@ struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) if (!atomic_inc_unless_negative(&sd->s_active)) return NULL; - if (likely(!sysfs_ignore_lockdep(sd))) + if (sd->s_flags & SYSFS_FLAG_LOCKDEP) rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_); return sd; } @@ -169,7 +169,7 @@ void sysfs_put_active(struct sysfs_dirent *sd) if (unlikely(!sd)) return; - if (likely(!sysfs_ignore_lockdep(sd))) + if (sd->s_flags & SYSFS_FLAG_LOCKDEP) rwsem_release(&sd->dep_map, 1, _RET_IP_); v = atomic_dec_return(&sd->s_active); if (likely(v != SD_DEACTIVATED_BIAS)) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index a68cbef3a674..e4eca285b390 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -58,7 +58,7 @@ static struct sysfs_open_file *sysfs_of(struct file *file) */ static const struct kernfs_ops *kernfs_ops(struct sysfs_dirent *sd) { - if (!sysfs_ignore_lockdep(sd)) + if (sd->s_flags & SYSFS_FLAG_LOCKDEP) lockdep_assert_held(sd); return sd->s_attr.ops; } @@ -71,7 +71,7 @@ static const struct sysfs_ops *sysfs_file_ops(struct sysfs_dirent *sd) { struct kobject *kobj = sd->s_parent->priv; - if (!sysfs_ignore_lockdep(sd)) + if (sd->s_flags & SYSFS_FLAG_LOCKDEP) lockdep_assert_held(sd); return kobj->ktype ? kobj->ktype->sysfs_ops : NULL; } @@ -942,6 +942,7 @@ int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, const struct attribute *attr, bool is_bin, umode_t mode, const void *ns) { + struct lock_class_key *key = NULL; const struct kernfs_ops *ops; struct sysfs_dirent *sd; loff_t size; @@ -981,8 +982,12 @@ int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, size = battr->size; } - sd = kernfs_create_file_ns(dir_sd, attr->name, mode, size, - ops, (void *)attr, ns); +#ifdef CONFIG_DEBUG_LOCK_ALLOC + if (!attr->ignore_lockdep) + key = attr->key ?: (struct lock_class_key *)&attr->skey; +#endif + sd = kernfs_create_file_ns_key(dir_sd, attr->name, mode, size, + ops, (void *)attr, ns, key); if (IS_ERR(sd)) { if (PTR_ERR(sd) == -EEXIST) sysfs_warn_dup(dir_sd, attr->name); @@ -992,7 +997,7 @@ int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, } /** - * kernfs_create_file_ns - create a file + * kernfs_create_file_ns_key - create a file * @parent: directory to create the file in * @name: name of the file * @mode: mode of the file @@ -1000,14 +1005,16 @@ int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, * @ops: kernfs operations for the file * @priv: private data for the file * @ns: optional namespace tag of the file + * @key: lockdep key for the file's active_ref, %NULL to disable lockdep * * Returns the created node on success, ERR_PTR() value on error. */ -struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent, - const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, - void *priv, const void *ns) +struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns, + struct lock_class_key *key) { struct sysfs_addrm_cxt acxt; struct sysfs_dirent *sd; @@ -1022,7 +1029,13 @@ struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent, sd->s_attr.size = size; sd->s_ns = ns; sd->priv = priv; - sysfs_dirent_init_lockdep(sd); + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + if (key) { + lockdep_init_map(&sd->dep_map, "s_active", key, 0); + sd->s_flags |= SYSFS_FLAG_LOCKDEP; + } +#endif /* * sd->s_attr.ops is accesible only while holding active ref. We diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index c86456c9b19e..e93f8b845611 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -92,43 +92,13 @@ struct sysfs_dirent { #define SYSFS_FLAG_NS 0x0020 #define SYSFS_FLAG_HAS_SEQ_SHOW 0x0040 #define SYSFS_FLAG_HAS_MMAP 0x0080 +#define SYSFS_FLAG_LOCKDEP 0x0100 static inline unsigned int sysfs_type(struct sysfs_dirent *sd) { return sd->s_flags & SYSFS_TYPE_MASK; } -#ifdef CONFIG_DEBUG_LOCK_ALLOC - -#define sysfs_dirent_init_lockdep(sd) \ -do { \ - struct attribute *attr = sd->priv; \ - struct lock_class_key *key = attr->key; \ - if (!key) \ - key = &attr->skey; \ - \ - lockdep_init_map(&sd->dep_map, "s_active", key, 0); \ -} while (0) - -/* Test for attributes that want to ignore lockdep for read-locking */ -static inline bool sysfs_ignore_lockdep(struct sysfs_dirent *sd) -{ - struct attribute *attr = sd->priv; - - return sysfs_type(sd) == SYSFS_KOBJ_ATTR && attr->ignore_lockdep; -} - -#else - -#define sysfs_dirent_init_lockdep(sd) do {} while (0) - -static inline bool sysfs_ignore_lockdep(struct sysfs_dirent *sd) -{ - return true; -} - -#endif - /* * Context structure to be used while adding/removing nodes. */ diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index f20796ecc76e..105d09dcb064 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -11,6 +11,7 @@ #include #include #include +#include struct file; struct iattr; @@ -62,6 +63,10 @@ struct kernfs_ops { loff_t off); int (*mmap)(struct sysfs_open_file *of, struct vm_area_struct *vma); + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lock_class_key lockdep_key; +#endif }; #ifdef CONFIG_SYSFS @@ -69,11 +74,12 @@ struct kernfs_ops { struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns); -struct sysfs_dirent *kernfs_create_file_ns(struct sysfs_dirent *parent, - const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, - void *priv, const void *ns); +struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns, + struct lock_class_key *key); struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, const char *name, struct sysfs_dirent *target); @@ -94,9 +100,10 @@ kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, { return ERR_PTR(-ENOSYS); } static inline struct sysfs_dirent * -kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name, - umode_t mode, loff_t size, const struct kernfs_ops *ops, - void *priv, const void *ns) +kernfs_create_file_ns_key(struct sysfs_dirent *parent, const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, void *priv, + const void *ns, struct lock_class_key *key) { return ERR_PTR(-ENOSYS); } static inline struct sysfs_dirent * @@ -131,6 +138,20 @@ kernfs_create_dir(struct sysfs_dirent *parent, const char *name, void *priv) return kernfs_create_dir_ns(parent, name, priv, NULL); } +static inline struct sysfs_dirent * +kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name, + umode_t mode, loff_t size, const struct kernfs_ops *ops, + void *priv, const void *ns) +{ + struct lock_class_key *key = NULL; + +#ifdef CONFIG_DEBUG_LOCK_ALLOC + key = (struct lock_class_key *)&ops->lockdep_key; +#endif + return kernfs_create_file_ns_key(parent, name, mode, size, ops, priv, + ns, key); +} + static inline struct sysfs_dirent * kernfs_create_file(struct sysfs_dirent *parent, const char *name, umode_t mode, loff_t size, const struct kernfs_ops *ops, void *priv) -- cgit v1.2.3-59-g8ed1b From ccf73cf336dc55bc52748205dee998d2fd4a8808 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:30 -0500 Subject: sysfs, kernfs: introduce kernfs[_find_and]_get() and kernfs_put() Introduce kernfs interface for finding, getting and putting sysfs_dirents. * sysfs_find_dirent() is renamed to kernfs_find_ns() and lockdep assertion for sysfs_mutex is added. * sysfs_get_dirent_ns() is renamed to kernfs_find_and_get(). * Macro inline dancing around __sysfs_get/put() are removed and kernfs_get/put() are made proper functions implemented in fs/sysfs/dir.c. While the conversions are mostly equivalent, there's one difference - kernfs_get() doesn't return the input param as its return value. This change is intentional. While passing through the input increases writability in some areas, it is unnecessary and has been shown to cause confusion regarding how the last ref is handled. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/sysfs/dir.c | 117 ++++++++++++++++++++++++++++--------------------- fs/sysfs/file.c | 41 +++++++++-------- fs/sysfs/group.c | 30 +++++++------ fs/sysfs/inode.c | 5 ++- fs/sysfs/mount.c | 14 ------ fs/sysfs/symlink.c | 16 ++++--- fs/sysfs/sysfs.h | 22 ---------- include/linux/kernfs.h | 19 ++++++++ include/linux/sysfs.h | 35 ++++++--------- 9 files changed, 151 insertions(+), 148 deletions(-) (limited to 'include/linux') diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 8f2d577b5f64..0d806efcc9a6 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -240,10 +240,31 @@ static void sysfs_free_ino(unsigned int ino) spin_unlock(&sysfs_ino_lock); } -void release_sysfs_dirent(struct sysfs_dirent *sd) +/** + * kernfs_get - get a reference count on a sysfs_dirent + * @sd: the target sysfs_dirent + */ +void kernfs_get(struct sysfs_dirent *sd) +{ + if (sd) { + WARN_ON(!atomic_read(&sd->s_count)); + atomic_inc(&sd->s_count); + } +} +EXPORT_SYMBOL_GPL(kernfs_get); + +/** + * kernfs_put - put a reference count on a sysfs_dirent + * @sd: the target sysfs_dirent + * + * Put a reference count of @sd and destroy it if it reached zero. + */ +void kernfs_put(struct sysfs_dirent *sd) { struct sysfs_dirent *parent_sd; + if (!sd || !atomic_dec_and_test(&sd->s_count)) + return; repeat: /* Moving/renaming is always done while holding reference. * sd->s_parent won't change beneath us. @@ -255,7 +276,7 @@ void release_sysfs_dirent(struct sysfs_dirent *sd) parent_sd ? parent_sd->s_name : "", sd->s_name); if (sysfs_type(sd) == SYSFS_KOBJ_LINK) - sysfs_put(sd->s_symlink.target_sd); + kernfs_put(sd->s_symlink.target_sd); if (sysfs_type(sd) & SYSFS_COPY_NAME) kfree(sd->s_name); if (sd->s_iattr && sd->s_iattr->ia_secdata) @@ -269,6 +290,7 @@ void release_sysfs_dirent(struct sysfs_dirent *sd) if (sd && atomic_dec_and_test(&sd->s_count)) goto repeat; } +EXPORT_SYMBOL_GPL(kernfs_put); static int sysfs_dentry_delete(const struct dentry *dentry) { @@ -331,7 +353,7 @@ out_bad: static void sysfs_dentry_release(struct dentry *dentry) { - sysfs_put(dentry->d_fsdata); + kernfs_put(dentry->d_fsdata); } const struct dentry_operations sysfs_dentry_ops = { @@ -433,7 +455,8 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, return -EINVAL; sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); - sd->s_parent = sysfs_get(parent_sd); + sd->s_parent = parent_sd; + kernfs_get(parent_sd); ret = sysfs_link_sibling(sd); if (ret) @@ -553,36 +576,33 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) sysfs_deactivate(sd); sysfs_unmap_bin_file(sd); - sysfs_put(sd); + kernfs_put(sd); } } /** - * sysfs_find_dirent - find sysfs_dirent with the given name - * @parent_sd: sysfs_dirent to search under - * @name: name to look for - * @ns: the namespace tag to use - * - * Look for sysfs_dirent with name @name under @parent_sd. - * - * LOCKING: - * mutex_lock(sysfs_mutex) + * kernfs_find_ns - find sysfs_dirent with the given name + * @parent: sysfs_dirent to search under + * @name: name to look for + * @ns: the namespace tag to use * - * RETURNS: - * Pointer to sysfs_dirent if found, NULL if not. + * Look for sysfs_dirent with name @name under @parent. Returns pointer to + * the found sysfs_dirent on success, %NULL on failure. */ -struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, - const unsigned char *name, - const void *ns) +static struct sysfs_dirent *kernfs_find_ns(struct sysfs_dirent *parent, + const unsigned char *name, + const void *ns) { - struct rb_node *node = parent_sd->s_dir.children.rb_node; - bool has_ns = parent_sd->s_flags & SYSFS_FLAG_NS; + struct rb_node *node = parent->s_dir.children.rb_node; + bool has_ns = parent->s_flags & SYSFS_FLAG_NS; unsigned int hash; + lockdep_assert_held(&sysfs_mutex); + if (has_ns != (bool)ns) { WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", has_ns ? "required" : "invalid", - parent_sd->s_name, name); + parent->s_name, name); return NULL; } @@ -604,34 +624,28 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, } /** - * sysfs_get_dirent_ns - find and get sysfs_dirent with the given name - * @parent_sd: sysfs_dirent to search under - * @name: name to look for - * @ns: the namespace tag to use - * - * Look for sysfs_dirent with name @name under @parent_sd and get - * it if found. - * - * LOCKING: - * Kernel thread context (may sleep). Grabs sysfs_mutex. + * kernfs_find_and_get_ns - find and get sysfs_dirent with the given name + * @parent: sysfs_dirent to search under + * @name: name to look for + * @ns: the namespace tag to use * - * RETURNS: - * Pointer to sysfs_dirent if found, NULL if not. + * Look for sysfs_dirent with name @name under @parent and get a reference + * if found. This function may sleep and returns pointer to the found + * sysfs_dirent on success, %NULL on failure. */ -struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, - const unsigned char *name, - const void *ns) +struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, + const char *name, const void *ns) { struct sysfs_dirent *sd; mutex_lock(&sysfs_mutex); - sd = sysfs_find_dirent(parent_sd, name, ns); - sysfs_get(sd); + sd = kernfs_find_ns(parent, name, ns); + kernfs_get(sd); mutex_unlock(&sysfs_mutex); return sd; } -EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns); +EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); /** * kernfs_create_dir_ns - create a directory @@ -667,7 +681,7 @@ struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, if (!rc) return sd; - sysfs_put(sd); + kernfs_put(sd); return ERR_PTR(rc); } @@ -716,14 +730,15 @@ static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry, if (parent_sd->s_flags & SYSFS_FLAG_NS) ns = sysfs_info(dir->i_sb)->ns; - sd = sysfs_find_dirent(parent_sd, dentry->d_name.name, ns); + sd = kernfs_find_ns(parent_sd, dentry->d_name.name, ns); /* no such entry */ if (!sd) { ret = ERR_PTR(-ENOENT); goto out_unlock; } - dentry->d_fsdata = sysfs_get(sd); + kernfs_get(sd); + dentry->d_fsdata = sd; /* attach dentry and inode */ inode = sysfs_get_inode(dir->i_sb, sd); @@ -859,7 +874,7 @@ int kernfs_remove_by_name_ns(struct sysfs_dirent *dir_sd, const char *name, sysfs_addrm_start(&acxt); - sd = sysfs_find_dirent(dir_sd, name, ns); + sd = kernfs_find_ns(dir_sd, name, ns); if (sd) __kernfs_remove(&acxt, sd); @@ -925,7 +940,7 @@ int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, goto out; /* nothing to rename */ error = -EEXIST; - if (sysfs_find_dirent(new_parent, new_name, new_ns)) + if (kernfs_find_ns(new_parent, new_name, new_ns)) goto out; /* rename sysfs_dirent */ @@ -943,8 +958,8 @@ int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, * Move to the appropriate place in the appropriate directories rbtree. */ sysfs_unlink_sibling(sd); - sysfs_get(new_parent); - sysfs_put(sd->s_parent); + kernfs_get(new_parent); + kernfs_put(sd->s_parent); sd->s_ns = new_ns; sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); sd->s_parent = new_parent; @@ -1000,7 +1015,7 @@ static inline unsigned char dt_type(struct sysfs_dirent *sd) static int sysfs_dir_release(struct inode *inode, struct file *filp) { - sysfs_put(filp->private_data); + kernfs_put(filp->private_data); return 0; } @@ -1011,7 +1026,7 @@ static struct sysfs_dirent *sysfs_dir_pos(const void *ns, int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && pos->s_parent == parent_sd && hash == pos->s_hash; - sysfs_put(pos); + kernfs_put(pos); if (!valid) pos = NULL; } @@ -1075,8 +1090,10 @@ static int sysfs_readdir(struct file *file, struct dir_context *ctx) unsigned int type = dt_type(pos); int len = strlen(name); ino_t ino = pos->s_ino; + ctx->pos = pos->s_hash; - file->private_data = sysfs_get(pos); + file->private_data = pos; + kernfs_get(pos); mutex_unlock(&sysfs_mutex); if (!dir_emit(ctx, name, len, ino, type)) diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index e4eca285b390..7f0a79fa2ed8 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -881,19 +881,19 @@ void sysfs_notify(struct kobject *k, const char *dir, const char *attr) struct sysfs_dirent *sd = k->sd, *tmp; if (sd && dir) - sd = sysfs_get_dirent(sd, dir); + sd = kernfs_find_and_get(sd, dir); else - sysfs_get(sd); + kernfs_get(sd); if (sd && attr) { - tmp = sysfs_get_dirent(sd, attr); - sysfs_put(sd); + tmp = kernfs_find_and_get(sd, attr); + kernfs_put(sd); sd = tmp; } if (sd) { kernfs_notify(sd); - sysfs_put(sd); + kernfs_put(sd); } } EXPORT_SYMBOL_GPL(sysfs_notify); @@ -1052,7 +1052,7 @@ struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *parent, sysfs_addrm_finish(&acxt); if (rc) { - sysfs_put(sd); + kernfs_put(sd); return ERR_PTR(rc); } return sd; @@ -1106,16 +1106,18 @@ int sysfs_add_file_to_group(struct kobject *kobj, struct sysfs_dirent *dir_sd; int error; - if (group) - dir_sd = sysfs_get_dirent(kobj->sd, group); - else - dir_sd = sysfs_get(kobj->sd); + if (group) { + dir_sd = kernfs_find_and_get(kobj->sd, group); + } else { + dir_sd = kobj->sd; + kernfs_get(dir_sd); + } if (!dir_sd) return -ENOENT; error = sysfs_add_file(dir_sd, attr, false); - sysfs_put(dir_sd); + kernfs_put(dir_sd); return error; } @@ -1135,7 +1137,7 @@ int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, struct iattr newattrs; int rc; - sd = sysfs_get_dirent(kobj->sd, attr->name); + sd = kernfs_find_and_get(kobj->sd, attr->name); if (!sd) return -ENOENT; @@ -1144,7 +1146,7 @@ int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, rc = kernfs_setattr(sd, &newattrs); - sysfs_put(sd); + kernfs_put(sd); return rc; } EXPORT_SYMBOL_GPL(sysfs_chmod_file); @@ -1185,13 +1187,16 @@ void sysfs_remove_file_from_group(struct kobject *kobj, { struct sysfs_dirent *dir_sd; - if (group) - dir_sd = sysfs_get_dirent(kobj->sd, group); - else - dir_sd = sysfs_get(kobj->sd); + if (group) { + dir_sd = kernfs_find_and_get(kobj->sd, group); + } else { + dir_sd = kobj->sd; + kernfs_get(dir_sd); + } + if (dir_sd) { kernfs_remove_by_name(dir_sd, attr->name); - sysfs_put(dir_sd); + kernfs_put(dir_sd); } } EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 9f65cd97a2d7..7177532b8f7b 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -108,13 +108,13 @@ static int internal_create_group(struct kobject *kobj, int update, } } else sd = kobj->sd; - sysfs_get(sd); + kernfs_get(sd); error = create_files(sd, kobj, grp, update); if (error) { if (grp->name) kernfs_remove(sd); } - sysfs_put(sd); + kernfs_put(sd); return error; } @@ -208,21 +208,23 @@ void sysfs_remove_group(struct kobject *kobj, struct sysfs_dirent *sd; if (grp->name) { - sd = sysfs_get_dirent(dir_sd, grp->name); + sd = kernfs_find_and_get(dir_sd, grp->name); if (!sd) { WARN(!sd, KERN_WARNING "sysfs group %p not found for kobject '%s'\n", grp, kobject_name(kobj)); return; } - } else - sd = sysfs_get(dir_sd); + } else { + sd = dir_sd; + kernfs_get(sd); + } remove_files(sd, kobj, grp); if (grp->name) kernfs_remove(sd); - sysfs_put(sd); + kernfs_put(sd); } EXPORT_SYMBOL_GPL(sysfs_remove_group); @@ -263,7 +265,7 @@ int sysfs_merge_group(struct kobject *kobj, struct attribute *const *attr; int i; - dir_sd = sysfs_get_dirent(kobj->sd, grp->name); + dir_sd = kernfs_find_and_get(kobj->sd, grp->name); if (!dir_sd) return -ENOENT; @@ -273,7 +275,7 @@ int sysfs_merge_group(struct kobject *kobj, while (--i >= 0) kernfs_remove_by_name(dir_sd, (*--attr)->name); } - sysfs_put(dir_sd); + kernfs_put(dir_sd); return error; } @@ -290,11 +292,11 @@ void sysfs_unmerge_group(struct kobject *kobj, struct sysfs_dirent *dir_sd; struct attribute *const *attr; - dir_sd = sysfs_get_dirent(kobj->sd, grp->name); + dir_sd = kernfs_find_and_get(kobj->sd, grp->name); if (dir_sd) { for (attr = grp->attrs; *attr; ++attr) kernfs_remove_by_name(dir_sd, (*attr)->name); - sysfs_put(dir_sd); + kernfs_put(dir_sd); } } EXPORT_SYMBOL_GPL(sysfs_unmerge_group); @@ -312,12 +314,12 @@ int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name, struct sysfs_dirent *dir_sd; int error = 0; - dir_sd = sysfs_get_dirent(kobj->sd, group_name); + dir_sd = kernfs_find_and_get(kobj->sd, group_name); if (!dir_sd) return -ENOENT; error = sysfs_create_link_sd(dir_sd, target, link_name); - sysfs_put(dir_sd); + kernfs_put(dir_sd); return error; } @@ -334,10 +336,10 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, { struct sysfs_dirent *dir_sd; - dir_sd = sysfs_get_dirent(kobj->sd, group_name); + dir_sd = kernfs_find_and_get(kobj->sd, group_name); if (dir_sd) { kernfs_remove_by_name(dir_sd, link_name); - sysfs_put(dir_sd); + kernfs_put(dir_sd); } } EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group); diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index b3c717ab3496..bfe4478f82bf 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -254,7 +254,8 @@ int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) { - inode->i_private = sysfs_get(sd); + kernfs_get(sd); + inode->i_private = sd; inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; inode->i_op = &sysfs_inode_operations; @@ -321,7 +322,7 @@ void sysfs_evict_inode(struct inode *inode) truncate_inode_pages(&inode->i_data, 0); clear_inode(inode); - sysfs_put(sd); + kernfs_put(sd); } int sysfs_permission(struct inode *inode, int mask) diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 8c24bce2f4ae..852d11519f98 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -184,17 +184,3 @@ out_err: sysfs_dir_cachep = NULL; goto out; } - -#undef sysfs_get -struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd) -{ - return __sysfs_get(sd); -} -EXPORT_SYMBOL_GPL(sysfs_get); - -#undef sysfs_put -void sysfs_put(struct sysfs_dirent *sd) -{ - __sysfs_put(sd); -} -EXPORT_SYMBOL_GPL(sysfs_put); diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 76efeab6db4e..b137aa3a486c 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -44,7 +44,7 @@ struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, if (parent->s_flags & SYSFS_FLAG_NS) sd->s_ns = target->s_ns; sd->s_symlink.target_sd = target; - sysfs_get(target); /* ref owned by symlink */ + kernfs_get(target); /* ref owned by symlink */ sysfs_addrm_start(&acxt); error = sysfs_add_one(&acxt, sd, parent); @@ -53,7 +53,7 @@ struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, if (!error) return sd; - sysfs_put(sd); + kernfs_put(sd); return ERR_PTR(error); } @@ -72,15 +72,17 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, * sysfs_remove_dir() for details. */ spin_lock(&sysfs_symlink_target_lock); - if (target->sd) - target_sd = sysfs_get(target->sd); + if (target->sd) { + target_sd = target->sd; + kernfs_get(target_sd); + } spin_unlock(&sysfs_symlink_target_lock); if (!target_sd) return -ENOENT; sd = kernfs_create_link(parent_sd, name, target_sd); - sysfs_put(target_sd); + kernfs_put(target_sd); if (!IS_ERR(sd)) return 0; @@ -216,7 +218,7 @@ int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, old_ns = targ->sd->s_ns; result = -ENOENT; - sd = sysfs_get_dirent_ns(parent_sd, old, old_ns); + sd = kernfs_find_and_get_ns(parent_sd, old, old_ns); if (!sd) goto out; @@ -229,7 +231,7 @@ int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, result = kernfs_rename_ns(sd, parent_sd, new, new_ns); out: - sysfs_put(sd); + kernfs_put(sd); return result; } EXPORT_SYMBOL_GPL(sysfs_rename_link_ns); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index e93f8b845611..85315e228408 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -141,30 +141,8 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, struct sysfs_dirent *parent_sd); void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); -struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, - const unsigned char *name, - const void *ns); struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type); -void release_sysfs_dirent(struct sysfs_dirent *sd); - -static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) -{ - if (sd) { - WARN_ON(!atomic_read(&sd->s_count)); - atomic_inc(&sd->s_count); - } - return sd; -} -#define sysfs_get(sd) __sysfs_get(sd) - -static inline void __sysfs_put(struct sysfs_dirent *sd) -{ - if (sd && atomic_dec_and_test(&sd->s_count)) - release_sysfs_dirent(sd); -} -#define sysfs_put(sd) __sysfs_put(sd) - /* * inode.c */ diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 105d09dcb064..fd8f574ef2fe 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -71,6 +71,11 @@ struct kernfs_ops { #ifdef CONFIG_SYSFS +struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, + const char *name, const void *ns); +void kernfs_get(struct sysfs_dirent *sd); +void kernfs_put(struct sysfs_dirent *sd); + struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns); @@ -94,6 +99,14 @@ void kernfs_notify(struct sysfs_dirent *sd); #else /* CONFIG_SYSFS */ +static inline struct sysfs_dirent * +kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, + const void *ns) +{ return NULL; } + +static inline void kernfs_get(struct sysfs_dirent *sd) { } +static inline void kernfs_put(struct sysfs_dirent *sd) { } + static inline struct sysfs_dirent * kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns) @@ -132,6 +145,12 @@ static inline void kernfs_notify(struct sysfs_dirent *sd) { } #endif /* CONFIG_SYSFS */ +static inline struct sysfs_dirent * +kernfs_find_and_get(struct sysfs_dirent *sd, const char *name) +{ + return kernfs_find_and_get_ns(sd, name, NULL); +} + static inline struct sysfs_dirent * kernfs_create_dir(struct sysfs_dirent *parent, const char *name, void *priv) { diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 0ab2b023b613..cd8f90bf51a7 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -243,11 +243,6 @@ void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, const char *link_name); void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr); -struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, - const unsigned char *name, - const void *ns); -struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd); -void sysfs_put(struct sysfs_dirent *sd); int __must_check sysfs_init(void); @@ -417,19 +412,6 @@ static inline void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr) { } -static inline struct sysfs_dirent * -sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, const unsigned char *name, - const void *ns) -{ - return NULL; -} -static inline struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd) -{ - return NULL; -} -static inline void sysfs_put(struct sysfs_dirent *sd) -{ -} static inline int __must_check sysfs_init(void) { @@ -456,15 +438,26 @@ static inline int sysfs_rename_link(struct kobject *kobj, struct kobject *target return sysfs_rename_link_ns(kobj, target, old_name, new_name, NULL); } +static inline void sysfs_notify_dirent(struct sysfs_dirent *sd) +{ + kernfs_notify(sd); +} + static inline struct sysfs_dirent * sysfs_get_dirent(struct sysfs_dirent *parent_sd, const unsigned char *name) { - return sysfs_get_dirent_ns(parent_sd, name, NULL); + return kernfs_find_and_get(parent_sd, name); } -static inline void sysfs_notify_dirent(struct sysfs_dirent *sd) +static inline struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd) { - kernfs_notify(sd); + kernfs_get(sd); + return sd; +} + +static inline void sysfs_put(struct sysfs_dirent *sd) +{ + kernfs_put(sd); } #endif /* _SYSFS_H_ */ -- cgit v1.2.3-59-g8ed1b From ba7443bc656e5236c316b2acacc8b551f872910f Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:40 -0500 Subject: sysfs, kernfs: implement kernfs_create/destroy_root() There currently is single kernfs hierarchy in the whole system which is used for sysfs. kernfs needs to support multiple hierarchies to allow other users. This patch introduces struct kernfs_root which serves as the root of each kernfs hierarchy and implements kernfs_create/destroy_root(). * Each kernfs_root is associated with a root sd (sysfs_dentry). The root is freed when the root sd is released and kernfs_destory_root() simply invokes kernfs_remove() on the root sd. sysfs_remove_one() is updated to handle release of the root sd. Note that ps_iattr update in sysfs_remove_one() is trivially updated for readability. * Root sd's are now dynamically allocated using sysfs_new_dirent(). Update sysfs_alloc_ino() so that it gives out ino from 1 so that the root sd still gets ino 1. * While kernfs currently only points to the root sd, it'll soon grow fields which are specific to each hierarchy. As determining a given sd's root will be necessary, sd->s_dir.root is added. This backlink fits better as a separate field in sd; however, sd->s_dir is inside union with space to spare, so use it to save space and provide kernfs_root() accessor to determine the root sd. * As hierarchies may be destroyed now, each mount needs to hold onto the hierarchy it's attached to. Update sysfs_fill_super() and sysfs_kill_sb() so that they get and put the kernfs_root respectively. * sysfs_root is replaced with kernfs_root which is dynamically created by invoking kernfs_create_root() from sysfs_init(). This patch doesn't introduce any visible behavior changes. v2: kernfs_create_root() forgot to set @sd->priv. Fixed. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 71 +++++++++++++++++++++++++++++++++++++++------ fs/kernfs/kernfs-internal.h | 20 +++++++++++++ fs/sysfs/mount.c | 29 +++++++++++------- include/linux/kernfs.h | 13 +++++++++ 4 files changed, 113 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index a4ca4de3cb21..246740a741ef 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -211,7 +211,7 @@ static int sysfs_alloc_ino(unsigned int *pino) retry: spin_lock(&sysfs_ino_lock); - rc = ida_get_new_above(&sysfs_ino_ida, 2, &ino); + rc = ida_get_new_above(&sysfs_ino_ida, 1, &ino); spin_unlock(&sysfs_ino_lock); if (rc == -EAGAIN) { @@ -253,9 +253,11 @@ EXPORT_SYMBOL_GPL(kernfs_get); void kernfs_put(struct sysfs_dirent *sd) { struct sysfs_dirent *parent_sd; + struct kernfs_root *root; if (!sd || !atomic_dec_and_test(&sd->s_count)) return; + root = kernfs_root(sd); repeat: /* Moving/renaming is always done while holding reference. * sd->s_parent won't change beneath us. @@ -278,8 +280,13 @@ void kernfs_put(struct sysfs_dirent *sd) kmem_cache_free(sysfs_dir_cachep, sd); sd = parent_sd; - if (sd && atomic_dec_and_test(&sd->s_count)) - goto repeat; + if (sd) { + if (atomic_dec_and_test(&sd->s_count)) + goto repeat; + } else { + /* just released the root sd, free @root too */ + kfree(root); + } } EXPORT_SYMBOL_GPL(kernfs_put); @@ -493,13 +500,15 @@ static void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, if (sd->s_flags & SYSFS_FLAG_REMOVED) return; - sysfs_unlink_sibling(sd); + if (sd->s_parent) { + sysfs_unlink_sibling(sd); - /* Update timestamps on the parent */ - ps_iattr = sd->s_parent->s_iattr; - if (ps_iattr) { - struct iattr *ps_iattrs = &ps_iattr->ia_iattr; - ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; + /* Update timestamps on the parent */ + ps_iattr = sd->s_parent->s_iattr; + if (ps_iattr) { + ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME; + ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME; + } } sd->s_flags |= SYSFS_FLAG_REMOVED; @@ -603,6 +612,49 @@ struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, } EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); +/** + * kernfs_create_root - create a new kernfs hierarchy + * @priv: opaque data associated with the new directory + * + * Returns the root of the new hierarchy on success, ERR_PTR() value on + * failure. + */ +struct kernfs_root *kernfs_create_root(void *priv) +{ + struct kernfs_root *root; + struct sysfs_dirent *sd; + + root = kzalloc(sizeof(*root), GFP_KERNEL); + if (!root) + return ERR_PTR(-ENOMEM); + + sd = sysfs_new_dirent("", S_IFDIR | S_IRUGO | S_IXUGO, SYSFS_DIR); + if (!sd) { + kfree(root); + return ERR_PTR(-ENOMEM); + } + + sd->s_flags &= ~SYSFS_FLAG_REMOVED; + sd->priv = priv; + sd->s_dir.root = root; + + root->sd = sd; + + return root; +} + +/** + * kernfs_destroy_root - destroy a kernfs hierarchy + * @root: root of the hierarchy to destroy + * + * Destroy the hierarchy anchored at @root by removing all existing + * directories and destroying @root. + */ +void kernfs_destroy_root(struct kernfs_root *root) +{ + kernfs_remove(root->sd); /* will also free @root */ +} + /** * kernfs_create_dir_ns - create a directory * @parent: parent in which to create a new directory @@ -626,6 +678,7 @@ struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, if (!sd) return ERR_PTR(-ENOMEM); + sd->s_dir.root = parent->s_dir.root; sd->s_ns = ns; sd->priv = priv; diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 62ae35f997f7..7dfe06278350 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -25,6 +25,12 @@ struct sysfs_elem_dir { unsigned long subdirs; /* children rbtree starts here and goes through sd->s_rb */ struct rb_root children; + + /* + * The kernfs hierarchy this directory belongs to. This fits + * better directly in sysfs_dirent but is here to save space. + */ + struct kernfs_root *root; }; struct sysfs_elem_symlink { @@ -104,6 +110,20 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd) return sd->s_flags & SYSFS_TYPE_MASK; } +/** + * kernfs_root - find out the kernfs_root a sysfs_dirent belongs to + * @sd: sysfs_dirent of interest + * + * Return the kernfs_root @sd belongs to. + */ +static inline struct kernfs_root *kernfs_root(struct sysfs_dirent *sd) +{ + /* if parent exists, it's always a dir; otherwise, @sd is a dir */ + if (sd->s_parent) + sd = sd->s_parent; + return sd->s_dir.root; +} + /* * Context structure to be used while adding/removing nodes. */ diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 7cbd1fce2826..0b5661b462f7 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -32,15 +32,8 @@ static const struct super_operations sysfs_ops = { .evict_inode = sysfs_evict_inode, }; -static struct sysfs_dirent sysfs_root = { - .s_name = "", - .s_count = ATOMIC_INIT(1), - .s_flags = SYSFS_DIR, - .s_mode = S_IFDIR | S_IRUGO | S_IXUGO, - .s_ino = 1, -}; - -struct sysfs_dirent *sysfs_root_sd = &sysfs_root; +static struct kernfs_root *sysfs_root; +struct sysfs_dirent *sysfs_root_sd; static int sysfs_fill_super(struct super_block *sb) { @@ -68,6 +61,7 @@ static int sysfs_fill_super(struct super_block *sb) pr_debug("%s: could not get root dentry!\n", __func__); return -ENOMEM; } + kernfs_get(sysfs_root_sd); root->d_fsdata = sysfs_root_sd; sb->s_root = root; sb->s_d_op = &sysfs_dentry_ops; @@ -138,11 +132,15 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, static void sysfs_kill_sb(struct super_block *sb) { struct sysfs_super_info *info = sysfs_info(sb); - /* Remove the superblock from fs_supers/s_instances + struct sysfs_dirent *root_sd = sb->s_root->d_fsdata; + + /* + * Remove the superblock from fs_supers/s_instances * so we can't find it, before freeing sysfs_super_info. */ kill_anon_super(sb); free_sysfs_super_info(info); + kernfs_put(root_sd); } static struct file_system_type sysfs_fs_type = { @@ -166,12 +164,21 @@ int __init sysfs_init(void) if (err) goto out_err; + sysfs_root = kernfs_create_root(NULL); + if (IS_ERR(sysfs_root)) { + err = PTR_ERR(sysfs_root); + goto out_err; + } + sysfs_root_sd = sysfs_root->sd; + err = register_filesystem(&sysfs_fs_type); if (err) - goto out_err; + goto out_destroy_root; return 0; +out_destroy_root: + kernfs_destroy_root(sysfs_root); out_err: kmem_cache_destroy(sysfs_dir_cachep); sysfs_dir_cachep = NULL; diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index fd8f574ef2fe..f75548b8ed7a 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -20,6 +20,11 @@ struct vm_area_struct; struct sysfs_dirent; +struct kernfs_root { + /* published fields */ + struct sysfs_dirent *sd; +}; + struct sysfs_open_file { /* published fields */ struct sysfs_dirent *sd; @@ -76,6 +81,9 @@ struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, void kernfs_get(struct sysfs_dirent *sd); void kernfs_put(struct sysfs_dirent *sd); +struct kernfs_root *kernfs_create_root(void *priv); +void kernfs_destroy_root(struct kernfs_root *root); + struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns); @@ -107,6 +115,11 @@ kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, static inline void kernfs_get(struct sysfs_dirent *sd) { } static inline void kernfs_put(struct sysfs_dirent *sd) { } +static inline struct kernfs_root *kernfs_create_root(void *priv) +{ return ERR_PTR(-ENOSYS); } + +static inline void kernfs_destroy_root(struct kernfs_root *root) { } + static inline struct sysfs_dirent * kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, const void *ns) -- cgit v1.2.3-59-g8ed1b From bc755553df9ab33f389c1a0a8bd0b4f4646e80ef Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:41 -0500 Subject: sysfs, kernfs: make inode number ida per kernfs_root kernfs is being updated to allow multiple sysfs_dirent hierarchies so that it can also be used by other users. Currently, inode number is allocated using a global ida, sysfs_ino_ida; however, inos for different hierarchies should be handled separately. This patch makes ino allocation per kernfs_root. sysfs_ino_ida is replaced by kernfs_root->ino_ida and sysfs_new_dirent() is updated to take @root and allocate ino from it. ida_simple_get/remove() are used instead of sysfs_ino_lock and sysfs_alloc/free_ino(). Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 47 +++++++++++++-------------------------------- fs/kernfs/file.c | 4 ++-- fs/kernfs/kernfs-internal.h | 3 ++- fs/kernfs/symlink.c | 3 ++- include/linux/kernfs.h | 4 ++++ 5 files changed, 23 insertions(+), 38 deletions(-) (limited to 'include/linux') diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 246740a741ef..eaffa83719d5 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -21,9 +21,6 @@ DEFINE_MUTEX(sysfs_mutex); #define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb) -static DEFINE_SPINLOCK(sysfs_ino_lock); -static DEFINE_IDA(sysfs_ino_ida); - /** * sysfs_name_hash * @name: Null terminated string to hash @@ -205,32 +202,6 @@ static void sysfs_deactivate(struct sysfs_dirent *sd) rwsem_release(&sd->dep_map, 1, _RET_IP_); } -static int sysfs_alloc_ino(unsigned int *pino) -{ - int ino, rc; - - retry: - spin_lock(&sysfs_ino_lock); - rc = ida_get_new_above(&sysfs_ino_ida, 1, &ino); - spin_unlock(&sysfs_ino_lock); - - if (rc == -EAGAIN) { - if (ida_pre_get(&sysfs_ino_ida, GFP_KERNEL)) - goto retry; - rc = -ENOMEM; - } - - *pino = ino; - return rc; -} - -static void sysfs_free_ino(unsigned int ino) -{ - spin_lock(&sysfs_ino_lock); - ida_remove(&sysfs_ino_ida, ino); - spin_unlock(&sysfs_ino_lock); -} - /** * kernfs_get - get a reference count on a sysfs_dirent * @sd: the target sysfs_dirent @@ -276,7 +247,7 @@ void kernfs_put(struct sysfs_dirent *sd) security_release_secctx(sd->s_iattr->ia_secdata, sd->s_iattr->ia_secdata_len); kfree(sd->s_iattr); - sysfs_free_ino(sd->s_ino); + ida_simple_remove(&root->ino_ida, sd->s_ino); kmem_cache_free(sysfs_dir_cachep, sd); sd = parent_sd; @@ -285,6 +256,7 @@ void kernfs_put(struct sysfs_dirent *sd) goto repeat; } else { /* just released the root sd, free @root too */ + ida_destroy(&root->ino_ida); kfree(root); } } @@ -360,10 +332,12 @@ const struct dentry_operations sysfs_dentry_ops = { .d_release = sysfs_dentry_release, }; -struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) +struct sysfs_dirent *sysfs_new_dirent(struct kernfs_root *root, + const char *name, umode_t mode, int type) { char *dup_name = NULL; struct sysfs_dirent *sd; + int ret; if (type & SYSFS_COPY_NAME) { name = dup_name = kstrdup(name, GFP_KERNEL); @@ -375,8 +349,10 @@ struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type) if (!sd) goto err_out1; - if (sysfs_alloc_ino(&sd->s_ino)) + ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL); + if (ret < 0) goto err_out2; + sd->s_ino = ret; atomic_set(&sd->s_count, 1); atomic_set(&sd->s_active, 0); @@ -628,8 +604,11 @@ struct kernfs_root *kernfs_create_root(void *priv) if (!root) return ERR_PTR(-ENOMEM); - sd = sysfs_new_dirent("", S_IFDIR | S_IRUGO | S_IXUGO, SYSFS_DIR); + ida_init(&root->ino_ida); + + sd = sysfs_new_dirent(root, "", S_IFDIR | S_IRUGO | S_IXUGO, SYSFS_DIR); if (!sd) { + ida_destroy(&root->ino_ida); kfree(root); return ERR_PTR(-ENOMEM); } @@ -674,7 +653,7 @@ struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, int rc; /* allocate */ - sd = sysfs_new_dirent(name, mode, SYSFS_DIR); + sd = sysfs_new_dirent(kernfs_root(parent), name, mode, SYSFS_DIR); if (!sd) return ERR_PTR(-ENOMEM); diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index fa172e86047f..990c97fa7045 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -775,8 +775,8 @@ struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *parent, struct sysfs_dirent *sd; int rc; - sd = sysfs_new_dirent(name, (mode & S_IALLUGO) | S_IFREG, - SYSFS_KOBJ_ATTR); + sd = sysfs_new_dirent(kernfs_root(parent), name, + (mode & S_IALLUGO) | S_IFREG, SYSFS_KOBJ_ATTR); if (!sd) return ERR_PTR(-ENOMEM); diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 7dfe06278350..466943d576f1 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -160,7 +160,8 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt); int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, struct sysfs_dirent *parent_sd); void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); -struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type); +struct sysfs_dirent *sysfs_new_dirent(struct kernfs_root *root, + const char *name, umode_t mode, int type); /* * file.c diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index af3570bb4303..004c16465594 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -30,7 +30,8 @@ struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, struct sysfs_addrm_cxt acxt; int error; - sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK); + sd = sysfs_new_dirent(kernfs_root(parent), name, S_IFLNK|S_IRWXUGO, + SYSFS_KOBJ_LINK); if (!sd) return ERR_PTR(-ENOMEM); diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index f75548b8ed7a..fad8b986800f 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -11,6 +11,7 @@ #include #include #include +#include #include struct file; @@ -23,6 +24,9 @@ struct sysfs_dirent; struct kernfs_root { /* published fields */ struct sysfs_dirent *sd; + + /* private fields, do not use outside kernfs proper */ + struct ida ino_ida; }; struct sysfs_open_file { -- cgit v1.2.3-59-g8ed1b From 4b93dc9b1c684d0587fe44d36bbfdf45bd3bea9d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 28 Nov 2013 14:54:43 -0500 Subject: sysfs, kernfs: prepare mount path for kernfs We're in the process of separating out core sysfs functionality into kernfs which will deal with sysfs_dirents directly. This patch rearranges mount path so that the kernfs and sysfs parts are separate. * As sysfs_super_info won't be visible outside kernfs proper, kernfs_super_ns() is added to allow kernfs users to access a super_block's namespace tag. * Generic mount operation is separated out into kernfs_mount_ns(). sysfs_mount() now just performs sysfs-specific permission check, acquires namespace tag, and invokes kernfs_mount_ns(). * Generic superblock release is separated out into kernfs_kill_sb() which can be used directly as file_system_type->kill_sb(). As sysfs needs to put the namespace tag, sysfs_kill_sb() wraps kernfs_kill_sb() with ns tag put. * sysfs_dir_cachep init and sysfs_inode_init() are separated out into kernfs_init(). kernfs_init() uses only small amount of memory and trying to handle and propagate kernfs_init() failure doesn't make much sense. Use SLAB_PANIC for sysfs_dir_cachep and make sysfs_inode_init() panic on failure. After this change, kernfs_init() should be called before sysfs_init(), fs/namespace.c::mnt_init() modified accordingly. Signed-off-by: Tejun Heo Cc: linux-fsdevel@vger.kernel.org Cc: Christoph Hellwig Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/inode.c | 5 ++- fs/kernfs/kernfs-internal.h | 2 +- fs/namespace.c | 2 + fs/sysfs/mount.c | 104 ++++++++++++++++++++++++++++++-------------- include/linux/kernfs.h | 28 ++++++++++++ 5 files changed, 106 insertions(+), 35 deletions(-) (limited to 'include/linux') diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index 9d4fab49ea20..b4cae6fd717b 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -37,9 +37,10 @@ static const struct inode_operations sysfs_inode_operations = { .setxattr = sysfs_setxattr, }; -int __init sysfs_inode_init(void) +void __init sysfs_inode_init(void) { - return bdi_init(&sysfs_backing_dev_info); + if (bdi_init(&sysfs_backing_dev_info)) + panic("failed to init sysfs_backing_dev_info"); } static struct sysfs_inode_attrs *sysfs_init_inode_attrs(struct sysfs_dirent *sd) diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 466943d576f1..0d949885389d 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -144,7 +144,7 @@ int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags); -int sysfs_inode_init(void); +void sysfs_inode_init(void); /* * dir.c diff --git a/fs/namespace.c b/fs/namespace.c index ac2ce8a766e1..a511ea003f89 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2790,6 +2790,8 @@ void __init mnt_init(void) for (u = 0; u < HASH_SIZE; u++) INIT_LIST_HEAD(&mountpoint_hashtable[u]); + kernfs_init(); + err = sysfs_init(); if (err) printk(KERN_WARNING "%s: sysfs_init error: %d\n", diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index f143b203a7e6..5384732700ba 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -86,18 +86,24 @@ static int sysfs_set_super(struct super_block *sb, void *data) return error; } -static void free_sysfs_super_info(struct sysfs_super_info *info) +/** + * kernfs_super_ns - determine the namespace tag of a kernfs super_block + * @sb: super_block of interest + * + * Return the namespace tag associated with kernfs super_block @sb. + */ +const void *kernfs_super_ns(struct super_block *sb) { - kobj_ns_drop(KOBJ_NS_TYPE_NET, (void *)info->ns); - kfree(info); + struct sysfs_super_info *info = sysfs_info(sb); + + return info->ns; } static struct dentry *sysfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - struct sysfs_super_info *info; - struct super_block *sb; - int error; + struct dentry *root; + void *ns; if (!(flags & MS_KERNMOUNT)) { if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) @@ -107,16 +113,44 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, return ERR_PTR(-EPERM); } + ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); + root = kernfs_mount_ns(fs_type, flags, sysfs_root, ns); + if (IS_ERR(root)) + kobj_ns_drop(KOBJ_NS_TYPE_NET, ns); + return root; +} + +/** + * kernfs_mount_ns - kernfs mount helper + * @fs_type: file_system_type of the fs being mounted + * @flags: mount flags specified for the mount + * @root: kernfs_root of the hierarchy being mounted + * @ns: optional namespace tag of the mount + * + * This is to be called from each kernfs user's file_system_type->mount() + * implementation, which should pass through the specified @fs_type and + * @flags, and specify the hierarchy and namespace tag to mount via @root + * and @ns, respectively. + * + * The return value can be passed to the vfs layer verbatim. + */ +struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, + struct kernfs_root *root, const void *ns) +{ + struct super_block *sb; + struct sysfs_super_info *info; + int error; + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return ERR_PTR(-ENOMEM); - info->root = sysfs_root; - info->ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); + info->root = root; + info->ns = ns; sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); if (IS_ERR(sb) || sb->s_fs_info != info) - free_sysfs_super_info(info); + kfree(info); if (IS_ERR(sb)) return ERR_CAST(sb); if (!sb->s_root) { @@ -132,6 +166,20 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, } static void sysfs_kill_sb(struct super_block *sb) +{ + kernfs_kill_sb(sb); + kobj_ns_drop(KOBJ_NS_TYPE_NET, (void *)kernfs_super_ns(sb)); +} + +/** + * kernfs_kill_sb - kill_sb for kernfs + * @sb: super_block being killed + * + * This can be used directly for file_system_type->kill_sb(). If a kernfs + * user needs extra cleanup, it can implement its own kill_sb() and call + * this function at the end. + */ +void kernfs_kill_sb(struct super_block *sb) { struct sysfs_super_info *info = sysfs_info(sb); struct sysfs_dirent *root_sd = sb->s_root->d_fsdata; @@ -141,7 +189,7 @@ static void sysfs_kill_sb(struct super_block *sb) * so we can't find it, before freeing sysfs_super_info. */ kill_anon_super(sb); - free_sysfs_super_info(info); + kfree(info); kernfs_put(root_sd); } @@ -152,37 +200,29 @@ static struct file_system_type sysfs_fs_type = { .fs_flags = FS_USERNS_MOUNT, }; -int __init sysfs_init(void) +void __init kernfs_init(void) { - int err; - sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache", sizeof(struct sysfs_dirent), - 0, 0, NULL); - if (!sysfs_dir_cachep) - return -ENOMEM; + 0, SLAB_PANIC, NULL); + sysfs_inode_init(); +} - err = sysfs_inode_init(); - if (err) - goto out_err; +int __init sysfs_init(void) +{ + int err; sysfs_root = kernfs_create_root(NULL); - if (IS_ERR(sysfs_root)) { - err = PTR_ERR(sysfs_root); - goto out_err; - } + if (IS_ERR(sysfs_root)) + return PTR_ERR(sysfs_root); + sysfs_root_sd = sysfs_root->sd; err = register_filesystem(&sysfs_fs_type); - if (err) - goto out_destroy_root; + if (err) { + kernfs_destroy_root(sysfs_root); + return err; + } return 0; - -out_destroy_root: - kernfs_destroy_root(sysfs_root); -out_err: - kmem_cache_destroy(sysfs_dir_cachep); - sysfs_dir_cachep = NULL; - return err; } diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index fad8b986800f..75fcbe5c9d65 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -18,6 +18,8 @@ struct file; struct iattr; struct seq_file; struct vm_area_struct; +struct super_block; +struct file_system_type; struct sysfs_dirent; @@ -109,6 +111,13 @@ void kernfs_enable_ns(struct sysfs_dirent *sd); int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); void kernfs_notify(struct sysfs_dirent *sd); +const void *kernfs_super_ns(struct super_block *sb); +struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, + struct kernfs_root *root, const void *ns); +void kernfs_kill_sb(struct super_block *sb); + +void kernfs_init(void); + #else /* CONFIG_SYSFS */ static inline struct sysfs_dirent * @@ -160,6 +169,18 @@ static inline int kernfs_setattr(struct sysfs_dirent *sd, static inline void kernfs_notify(struct sysfs_dirent *sd) { } +static inline const void *kernfs_super_ns(struct super_block *sb) +{ return NULL; } + +static inline struct dentry * +kernfs_mount_ns(struct file_system_type *fs_type, int flags, + struct kernfs_root *root, const void *ns) +{ return ERR_PTR(-ENOSYS); } + +static inline void kernfs_kill_sb(struct super_block *sb) { } + +static inline void kernfs_init(void) { } + #endif /* CONFIG_SYSFS */ static inline struct sysfs_dirent * @@ -201,4 +222,11 @@ static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, return kernfs_remove_by_name_ns(parent, name, NULL); } +static inline struct dentry * +kernfs_mount(struct file_system_type *fs_type, int flags, + struct kernfs_root *root) +{ + return kernfs_mount_ns(fs_type, flags, root, NULL); +} + #endif /* __LINUX_KERNFS_H */ -- cgit v1.2.3-59-g8ed1b From cf9e5a73aaff0204801dd19cb4bd91d32f32026a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 29 Nov 2013 17:18:32 -0500 Subject: sysfs, kernfs: make sysfs_dirent definition public sysfs_dirent includes some information which should be available to kernfs users - the type, flags, name and parent pointer. This patch moves sysfs_dirent definition from kernfs/kernfs-internal.h to include/linux/kernfs.h so that kernfs users can access them. The type part of flags is exported as enum kernfs_node_type, the flags kernfs_node_flag, sysfs_type() and kernfs_enable_ns() are moved to include/linux/kernfs.h and the former is updated to return the enum type. sysfs_dirent->s_parent and ->s_name are marked explicitly as public. This patch doesn't introduce any functional changes. v2: Flags exported too and kernfs_enable_ns() definition moved. v3: While moving kernfs_enable_ns() to include/linux/kernfs.h, v1 and v2 put the definition outside CONFIG_SYSFS replacing the dummy implementation with the actual implementation too. Unfortunately, this can lead to oops when !CONFIG_SYSFS because kernfs_enable_ns() may be called on a NULL @sd and now tries to dereference @sd instead of not doing anything. This issue was reported by Yuanhan Liu. Signed-off-by: Tejun Heo Reported-by: Yuanhan Liu Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 15 ------ fs/kernfs/kernfs-internal.h | 85 +------------------------------ include/linux/kernfs.h | 118 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 115 insertions(+), 103 deletions(-) (limited to 'include/linux') diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index eaffa83719d5..7c5b51793689 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -895,21 +895,6 @@ int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, return error; } -/** - * kernfs_enable_ns - enable namespace under a directory - * @sd: directory of interest, should be empty - * - * This is to be called right after @sd is created to enable namespace - * under it. All children of @sd must have non-NULL namespace tags and - * only the ones which match the super_block's tag will be visible. - */ -void kernfs_enable_ns(struct sysfs_dirent *sd) -{ - WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); - WARN_ON_ONCE(!RB_EMPTY_ROOT(&sd->s_dir.children)); - sd->s_flags |= SYSFS_FLAG_NS; -} - /* Relationship between s_mode and the DT_xxx types */ static inline unsigned char dt_type(struct sysfs_dirent *sd) { diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index ced0d6dadc7d..f33a7844e8fd 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -13,102 +13,19 @@ #include #include -#include #include #include -struct sysfs_open_dirent; - -/* type-specific structures for sysfs_dirent->s_* union members */ -struct sysfs_elem_dir { - unsigned long subdirs; - /* children rbtree starts here and goes through sd->s_rb */ - struct rb_root children; - - /* - * The kernfs hierarchy this directory belongs to. This fits - * better directly in sysfs_dirent but is here to save space. - */ - struct kernfs_root *root; -}; - -struct sysfs_elem_symlink { - struct sysfs_dirent *target_sd; -}; - -struct sysfs_elem_attr { - const struct kernfs_ops *ops; - struct sysfs_open_dirent *open; - loff_t size; -}; - struct sysfs_inode_attrs { struct iattr ia_iattr; void *ia_secdata; u32 ia_secdata_len; }; -/* - * sysfs_dirent - the building block of sysfs hierarchy. Each and - * every sysfs node is represented by single sysfs_dirent. - * - * As long as s_count reference is held, the sysfs_dirent itself is - * accessible. Dereferencing s_elem or any other outer entity - * requires s_active reference. - */ -struct sysfs_dirent { - atomic_t s_count; - atomic_t s_active; -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif - struct sysfs_dirent *s_parent; - const char *s_name; - - struct rb_node s_rb; - - union { - struct completion *completion; - struct sysfs_dirent *removed_list; - } u; - - const void *s_ns; /* namespace tag */ - unsigned int s_hash; /* ns + name hash */ - union { - struct sysfs_elem_dir s_dir; - struct sysfs_elem_symlink s_symlink; - struct sysfs_elem_attr s_attr; - }; - - void *priv; - - unsigned short s_flags; - umode_t s_mode; - unsigned int s_ino; - struct sysfs_inode_attrs *s_iattr; -}; - #define SD_DEACTIVATED_BIAS INT_MIN -#define SYSFS_TYPE_MASK 0x000f -#define SYSFS_DIR 0x0001 -#define SYSFS_KOBJ_ATTR 0x0002 -#define SYSFS_KOBJ_LINK 0x0004 -#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) -#define SYSFS_ACTIVE_REF SYSFS_KOBJ_ATTR - -#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK -#define SYSFS_FLAG_REMOVED 0x0010 -#define SYSFS_FLAG_NS 0x0020 -#define SYSFS_FLAG_HAS_SEQ_SHOW 0x0040 -#define SYSFS_FLAG_HAS_MMAP 0x0080 -#define SYSFS_FLAG_LOCKDEP 0x0100 - -static inline unsigned int sysfs_type(struct sysfs_dirent *sd) -{ - return sd->s_flags & SYSFS_TYPE_MASK; -} +/* SYSFS_TYPE_MASK and types are defined in include/linux/kernfs.h */ /** * kernfs_root - find out the kernfs_root a sysfs_dirent belongs to diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 75fcbe5c9d65..faaf4f29e33d 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include struct file; struct iattr; @@ -21,7 +24,92 @@ struct vm_area_struct; struct super_block; struct file_system_type; -struct sysfs_dirent; +struct sysfs_open_dirent; +struct sysfs_inode_attrs; + +enum kernfs_node_type { + SYSFS_DIR = 0x0001, + SYSFS_KOBJ_ATTR = 0x0002, + SYSFS_KOBJ_LINK = 0x0004, +}; + +#define SYSFS_TYPE_MASK 0x000f +#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) +#define SYSFS_ACTIVE_REF SYSFS_KOBJ_ATTR +#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK + +enum kernfs_node_flag { + SYSFS_FLAG_REMOVED = 0x0010, + SYSFS_FLAG_NS = 0x0020, + SYSFS_FLAG_HAS_SEQ_SHOW = 0x0040, + SYSFS_FLAG_HAS_MMAP = 0x0080, + SYSFS_FLAG_LOCKDEP = 0x0100, +}; + +/* type-specific structures for sysfs_dirent->s_* union members */ +struct sysfs_elem_dir { + unsigned long subdirs; + /* children rbtree starts here and goes through sd->s_rb */ + struct rb_root children; + + /* + * The kernfs hierarchy this directory belongs to. This fits + * better directly in sysfs_dirent but is here to save space. + */ + struct kernfs_root *root; +}; + +struct sysfs_elem_symlink { + struct sysfs_dirent *target_sd; +}; + +struct sysfs_elem_attr { + const struct kernfs_ops *ops; + struct sysfs_open_dirent *open; + loff_t size; +}; + +/* + * sysfs_dirent - the building block of sysfs hierarchy. Each and every + * sysfs node is represented by single sysfs_dirent. Most fields are + * private to kernfs and shouldn't be accessed directly by kernfs users. + * + * As long as s_count reference is held, the sysfs_dirent itself is + * accessible. Dereferencing s_elem or any other outer entity + * requires s_active reference. + */ +struct sysfs_dirent { + atomic_t s_count; + atomic_t s_active; +#ifdef CONFIG_DEBUG_LOCK_ALLOC + struct lockdep_map dep_map; +#endif + /* the following two fields are published */ + struct sysfs_dirent *s_parent; + const char *s_name; + + struct rb_node s_rb; + + union { + struct completion *completion; + struct sysfs_dirent *removed_list; + } u; + + const void *s_ns; /* namespace tag */ + unsigned int s_hash; /* ns + name hash */ + union { + struct sysfs_elem_dir s_dir; + struct sysfs_elem_symlink s_symlink; + struct sysfs_elem_attr s_attr; + }; + + void *priv; + + unsigned short s_flags; + umode_t s_mode; + unsigned int s_ino; + struct sysfs_inode_attrs *s_iattr; +}; struct kernfs_root { /* published fields */ @@ -82,6 +170,26 @@ struct kernfs_ops { #ifdef CONFIG_SYSFS +static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd) +{ + return sd->s_flags & SYSFS_TYPE_MASK; +} + +/** + * kernfs_enable_ns - enable namespace under a directory + * @sd: directory of interest, should be empty + * + * This is to be called right after @sd is created to enable namespace + * under it. All children of @sd must have non-NULL namespace tags and + * only the ones which match the super_block's tag will be visible. + */ +static inline void kernfs_enable_ns(struct sysfs_dirent *sd) +{ + WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); + WARN_ON_ONCE(!RB_EMPTY_ROOT(&sd->s_dir.children)); + sd->s_flags |= SYSFS_FLAG_NS; +} + struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, const void *ns); void kernfs_get(struct sysfs_dirent *sd); @@ -107,7 +215,6 @@ int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, const void *ns); int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, const char *new_name, const void *new_ns); -void kernfs_enable_ns(struct sysfs_dirent *sd); int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); void kernfs_notify(struct sysfs_dirent *sd); @@ -120,6 +227,11 @@ void kernfs_init(void); #else /* CONFIG_SYSFS */ +static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd) +{ return 0; } /* whatever */ + +static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { } + static inline struct sysfs_dirent * kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, const void *ns) @@ -161,8 +273,6 @@ static inline int kernfs_rename_ns(struct sysfs_dirent *sd, const char *new_name, const void *new_ns) { return -ENOSYS; } -static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { } - static inline int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr) { return -ENOSYS; } -- cgit v1.2.3-59-g8ed1b From ac9bba031001704a2339713cc12148857eccc5e5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 29 Nov 2013 17:19:09 -0500 Subject: sysfs, kernfs: implement kernfs_ns_enabled() fs/sysfs/symlink.c::sysfs_delete_link() tests @sd->s_flags for SYSFS_FLAG_NS. Let's add kernfs_ns_enabled() so that sysfs doesn't have to test sysfs_dirent flag directly. This makes things tidier for kernfs proper too. This is purely cosmetic. v2: To avoid possible NULL deref, use noop dummy implementation which always returns false when !CONFIG_SYSFS. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 10 +++++----- fs/kernfs/symlink.c | 2 +- fs/sysfs/symlink.c | 2 +- include/linux/kernfs.h | 14 ++++++++++++++ 4 files changed, 21 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 7c5b51793689..f51e0625e666 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -291,7 +291,7 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) goto out_bad; /* The sysfs dirent has been moved to a different namespace */ - if (sd->s_parent && (sd->s_parent->s_flags & SYSFS_FLAG_NS) && + if (sd->s_parent && kernfs_ns_enabled(sd->s_parent) && sysfs_info(dentry->d_sb)->ns != sd->s_ns) goto out_bad; @@ -414,7 +414,7 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt) int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, struct sysfs_dirent *parent_sd) { - bool has_ns = parent_sd->s_flags & SYSFS_FLAG_NS; + bool has_ns = kernfs_ns_enabled(parent_sd); struct sysfs_inode_attrs *ps_iattr; int ret; @@ -535,7 +535,7 @@ static struct sysfs_dirent *kernfs_find_ns(struct sysfs_dirent *parent, const void *ns) { struct rb_node *node = parent->s_dir.children.rb_node; - bool has_ns = parent->s_flags & SYSFS_FLAG_NS; + bool has_ns = kernfs_ns_enabled(parent); unsigned int hash; lockdep_assert_held(&sysfs_mutex); @@ -685,7 +685,7 @@ static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry, mutex_lock(&sysfs_mutex); - if (parent_sd->s_flags & SYSFS_FLAG_NS) + if (kernfs_ns_enabled(parent_sd)) ns = sysfs_info(dir->i_sb)->ns; sd = kernfs_find_ns(parent_sd, dentry->d_name.name, ns); @@ -968,7 +968,7 @@ static int sysfs_readdir(struct file *file, struct dir_context *ctx) return 0; mutex_lock(&sysfs_mutex); - if (parent_sd->s_flags & SYSFS_FLAG_NS) + if (kernfs_ns_enabled(parent_sd)) ns = sysfs_info(dentry->d_sb)->ns; for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos); diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index 004c16465594..12569a738837 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -35,7 +35,7 @@ struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, if (!sd) return ERR_PTR(-ENOMEM); - if (parent->s_flags & SYSFS_FLAG_NS) + if (kernfs_ns_enabled(parent)) sd->s_ns = target->s_ns; sd->s_symlink.target_sd = target; kernfs_get(target); /* ref owned by symlink */ diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 62f0e014ec48..1b8c9ed8511a 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -128,7 +128,7 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, * sysfs_remove_dir() for details. */ spin_lock(&sysfs_symlink_target_lock); - if (targ->sd && (kobj->sd->s_flags & SYSFS_FLAG_NS)) + if (targ->sd && kernfs_ns_enabled(kobj->sd)) ns = targ->sd->s_ns; spin_unlock(&sysfs_symlink_target_lock); kernfs_remove_by_name_ns(kobj->sd, name, ns); diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index faaf4f29e33d..d65541308419 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -190,6 +190,17 @@ static inline void kernfs_enable_ns(struct sysfs_dirent *sd) sd->s_flags |= SYSFS_FLAG_NS; } +/** + * kernfs_ns_enabled - test whether namespace is enabled + * @sd: the node to test + * + * Test whether namespace filtering is enabled for the children of @ns. + */ +static inline bool kernfs_ns_enabled(struct sysfs_dirent *sd) +{ + return sd->s_flags & SYSFS_FLAG_NS; +} + struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, const void *ns); void kernfs_get(struct sysfs_dirent *sd); @@ -232,6 +243,9 @@ static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd) static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { } +static inline bool kernfs_ns_enabled(struct sysfs_dirent *sd) +{ return false; } + static inline struct sysfs_dirent * kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, const void *ns) -- cgit v1.2.3-59-g8ed1b From d36240d26025bec95f3499e2401a56db98d9f01c Mon Sep 17 00:00:00 2001 From: Pali Rohár Date: Tue, 19 Nov 2013 11:18:03 +0100 Subject: power_supply: Add power_supply notifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds a notifier chain to the power_supply, this helps drivers in other subsystem to listen to changes in power supply subsystem. This would help to take some actions in those drivers on changing the power supply properties. One such scenario is to increase/decrease system performance based on the battery capacity/voltage. Another scenario is to adjust the h/w peak current detection voltage/current thresholds based on battery voltage/capacity. The notifier helps drivers to listen to changes in power_suppy susbystem without polling the power_supply properties Signed-off-by: Jenny TC Signed-off-by: Pali Rohár Acked-by: Jenny TC Signed-off-by: Anton Vorontsov --- drivers/power/power_supply_core.c | 18 ++++++++++++++++++ include/linux/power_supply.h | 8 ++++++++ 2 files changed, 26 insertions(+) (limited to 'include/linux') diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 557af943b2f5..6aac23cc6566 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,9 @@ struct class *power_supply_class; EXPORT_SYMBOL_GPL(power_supply_class); +ATOMIC_NOTIFIER_HEAD(power_supply_notifier); +EXPORT_SYMBOL_GPL(power_supply_notifier); + static struct device_type power_supply_dev_type; static bool __power_supply_is_supplied_by(struct power_supply *supplier, @@ -80,6 +84,8 @@ static void power_supply_changed_work(struct work_struct *work) class_for_each_device(power_supply_class, NULL, psy, __power_supply_changed_work); power_supply_update_leds(psy); + atomic_notifier_call_chain(&power_supply_notifier, + PSY_EVENT_PROP_CHANGED, psy); kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); spin_lock_irqsave(&psy->changed_lock, flags); } @@ -347,6 +353,18 @@ static void power_supply_dev_release(struct device *dev) kfree(dev); } +int power_supply_reg_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&power_supply_notifier, nb); +} +EXPORT_SYMBOL_GPL(power_supply_reg_notifier); + +void power_supply_unreg_notifier(struct notifier_block *nb) +{ + atomic_notifier_chain_unregister(&power_supply_notifier, nb); +} +EXPORT_SYMBOL_GPL(power_supply_unreg_notifier); + #ifdef CONFIG_THERMAL static int power_supply_read_temp(struct thermal_zone_device *tzd, unsigned long *temp) diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 5c2600630dc9..3e28fe188d17 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -16,6 +16,7 @@ #include #include #include +#include struct device; @@ -158,6 +159,10 @@ enum power_supply_type { POWER_SUPPLY_TYPE_USB_ACA, /* Accessory Charger Adapters */ }; +enum power_supply_notifier_events { + PSY_EVENT_PROP_CHANGED, +}; + union power_supply_propval { int intval; const char *strval; @@ -235,6 +240,9 @@ struct power_supply_info { int use_for_apm; }; +extern struct atomic_notifier_head power_supply_notifier; +extern int power_supply_reg_notifier(struct notifier_block *nb); +extern void power_supply_unreg_notifier(struct notifier_block *nb); extern struct power_supply *power_supply_get_by_name(const char *name); extern void power_supply_changed(struct power_supply *psy); extern int power_supply_am_i_supplied(struct power_supply *psy); -- cgit v1.2.3-59-g8ed1b From 2edb90ae421a0f65edcdef65ef9dd08e3228abbf Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Fri, 11 Oct 2013 09:37:45 +0200 Subject: ARM: at91: move at91_pmc.h to include/linux/clk/at91_pmc.h This patch moves at91_pmc.h header from machine specific directory (arch/arm/mach-at91/include/mach/at91_pmc.h) to clk include directory (include/linux/clk/at91_pmc.h). We need this to avoid reference to machine specific headers in clk drivers. Signed-off-by: Boris BREZILLON Acked-by: Felipe Balbi Acked-by: Mike Turquette Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/at91rm9200.c | 2 +- arch/arm/mach-at91/at91sam9260.c | 2 +- arch/arm/mach-at91/at91sam9261.c | 2 +- arch/arm/mach-at91/at91sam9263.c | 2 +- arch/arm/mach-at91/at91sam9g45.c | 2 +- arch/arm/mach-at91/at91sam9n12.c | 2 +- arch/arm/mach-at91/at91sam9rl.c | 2 +- arch/arm/mach-at91/at91sam9x5.c | 2 +- arch/arm/mach-at91/clock.c | 2 +- arch/arm/mach-at91/include/mach/at91_pmc.h | 190 ----------------------------- arch/arm/mach-at91/pm.c | 2 +- arch/arm/mach-at91/pm_slowclock.S | 2 +- arch/arm/mach-at91/sama5d3.c | 2 +- arch/arm/mach-at91/setup.c | 2 +- drivers/usb/gadget/atmel_usba_udc.c | 2 +- include/linux/clk/at91_pmc.h | 190 +++++++++++++++++++++++++++++ 16 files changed, 204 insertions(+), 204 deletions(-) delete mode 100644 arch/arm/mach-at91/include/mach/at91_pmc.h create mode 100644 include/linux/clk/at91_pmc.h (limited to 'include/linux') diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index 25805f2f6010..e47f5fd232f5 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c @@ -12,13 +12,13 @@ #include #include +#include #include #include #include #include #include -#include #include #include diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index d6a1fa85371d..6c821e562159 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -20,7 +21,6 @@ #include #include #include -#include #include "at91_aic.h" #include "at91_rstc.h" diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index 23ba1d8a1531..6276b4c1acfe 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include "at91_aic.h" #include "at91_rstc.h" diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 7eccb0fc57bc..37b90f4b990c 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -11,6 +11,7 @@ */ #include +#include #include #include @@ -18,7 +19,6 @@ #include #include #include -#include #include "at91_aic.h" #include "at91_rstc.h" diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 9405aa08b104..2f455ce35268 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -12,13 +12,13 @@ #include #include +#include #include #include #include #include #include -#include #include #include "at91_aic.h" diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c index 388ec3aec4b9..4ef088c62eab 100644 --- a/arch/arm/mach-at91/at91sam9n12.c +++ b/arch/arm/mach-at91/at91sam9n12.c @@ -8,12 +8,12 @@ #include #include +#include #include #include #include #include -#include #include #include "board.h" diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 0750ffb7e6b1..3651517abedf 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -10,6 +10,7 @@ */ #include +#include #include #include @@ -19,7 +20,6 @@ #include #include #include -#include #include "at91_aic.h" #include "at91_rstc.h" diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c index e8a2e075a1b8..3e8ec26e39dc 100644 --- a/arch/arm/mach-at91/at91sam9x5.c +++ b/arch/arm/mach-at91/at91sam9x5.c @@ -8,12 +8,12 @@ #include #include +#include #include #include #include #include -#include #include #include "board.h" diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c index 6b2630a92f71..5f02aea1021c 100644 --- a/arch/arm/mach-at91/clock.c +++ b/arch/arm/mach-at91/clock.c @@ -24,9 +24,9 @@ #include #include #include +#include #include -#include #include #include diff --git a/arch/arm/mach-at91/include/mach/at91_pmc.h b/arch/arm/mach-at91/include/mach/at91_pmc.h deleted file mode 100644 index c604cc69acb5..000000000000 --- a/arch/arm/mach-at91/include/mach/at91_pmc.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * arch/arm/mach-at91/include/mach/at91_pmc.h - * - * Copyright (C) 2005 Ivan Kokshaysky - * Copyright (C) SAN People - * - * Power Management Controller (PMC) - System peripherals registers. - * Based on AT91RM9200 datasheet revision E. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef AT91_PMC_H -#define AT91_PMC_H - -#ifndef __ASSEMBLY__ -extern void __iomem *at91_pmc_base; - -#define at91_pmc_read(field) \ - __raw_readl(at91_pmc_base + field) - -#define at91_pmc_write(field, value) \ - __raw_writel(value, at91_pmc_base + field) -#else -.extern at91_pmc_base -#endif - -#define AT91_PMC_SCER 0x00 /* System Clock Enable Register */ -#define AT91_PMC_SCDR 0x04 /* System Clock Disable Register */ - -#define AT91_PMC_SCSR 0x08 /* System Clock Status Register */ -#define AT91_PMC_PCK (1 << 0) /* Processor Clock */ -#define AT91RM9200_PMC_UDP (1 << 1) /* USB Devcice Port Clock [AT91RM9200 only] */ -#define AT91RM9200_PMC_MCKUDP (1 << 2) /* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */ -#define AT91RM9200_PMC_UHP (1 << 4) /* USB Host Port Clock [AT91RM9200 only] */ -#define AT91SAM926x_PMC_UHP (1 << 6) /* USB Host Port Clock [AT91SAM926x only] */ -#define AT91SAM926x_PMC_UDP (1 << 7) /* USB Devcice Port Clock [AT91SAM926x only] */ -#define AT91_PMC_PCK0 (1 << 8) /* Programmable Clock 0 */ -#define AT91_PMC_PCK1 (1 << 9) /* Programmable Clock 1 */ -#define AT91_PMC_PCK2 (1 << 10) /* Programmable Clock 2 */ -#define AT91_PMC_PCK3 (1 << 11) /* Programmable Clock 3 */ -#define AT91_PMC_PCK4 (1 << 12) /* Programmable Clock 4 [AT572D940HF only] */ -#define AT91_PMC_HCK0 (1 << 16) /* AHB Clock (USB host) [AT91SAM9261 only] */ -#define AT91_PMC_HCK1 (1 << 17) /* AHB Clock (LCD) [AT91SAM9261 only] */ - -#define AT91_PMC_PCER 0x10 /* Peripheral Clock Enable Register */ -#define AT91_PMC_PCDR 0x14 /* Peripheral Clock Disable Register */ -#define AT91_PMC_PCSR 0x18 /* Peripheral Clock Status Register */ - -#define AT91_CKGR_UCKR 0x1C /* UTMI Clock Register [some SAM9] */ -#define AT91_PMC_UPLLEN (1 << 16) /* UTMI PLL Enable */ -#define AT91_PMC_UPLLCOUNT (0xf << 20) /* UTMI PLL Start-up Time */ -#define AT91_PMC_BIASEN (1 << 24) /* UTMI BIAS Enable */ -#define AT91_PMC_BIASCOUNT (0xf << 28) /* UTMI BIAS Start-up Time */ - -#define AT91_CKGR_MOR 0x20 /* Main Oscillator Register [not on SAM9RL] */ -#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */ -#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass */ -#define AT91_PMC_MOSCRCEN (1 << 3) /* Main On-Chip RC Oscillator Enable [some SAM9] */ -#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */ -#define AT91_PMC_KEY (0x37 << 16) /* MOR Writing Key */ -#define AT91_PMC_MOSCSEL (1 << 24) /* Main Oscillator Selection [some SAM9] */ -#define AT91_PMC_CFDEN (1 << 25) /* Clock Failure Detector Enable [some SAM9] */ - -#define AT91_CKGR_MCFR 0x24 /* Main Clock Frequency Register */ -#define AT91_PMC_MAINF (0xffff << 0) /* Main Clock Frequency */ -#define AT91_PMC_MAINRDY (1 << 16) /* Main Clock Ready */ - -#define AT91_CKGR_PLLAR 0x28 /* PLL A Register */ -#define AT91_CKGR_PLLBR 0x2c /* PLL B Register */ -#define AT91_PMC_DIV (0xff << 0) /* Divider */ -#define AT91_PMC_PLLCOUNT (0x3f << 8) /* PLL Counter */ -#define AT91_PMC_OUT (3 << 14) /* PLL Clock Frequency Range */ -#define AT91_PMC_MUL (0x7ff << 16) /* PLL Multiplier */ -#define AT91_PMC_MUL_GET(n) ((n) >> 16 & 0x7ff) -#define AT91_PMC3_MUL (0x7f << 18) /* PLL Multiplier [SAMA5 only] */ -#define AT91_PMC3_MUL_GET(n) ((n) >> 18 & 0x7f) -#define AT91_PMC_USBDIV (3 << 28) /* USB Divisor (PLLB only) */ -#define AT91_PMC_USBDIV_1 (0 << 28) -#define AT91_PMC_USBDIV_2 (1 << 28) -#define AT91_PMC_USBDIV_4 (2 << 28) -#define AT91_PMC_USB96M (1 << 28) /* Divider by 2 Enable (PLLB only) */ - -#define AT91_PMC_MCKR 0x30 /* Master Clock Register */ -#define AT91_PMC_CSS (3 << 0) /* Master Clock Selection */ -#define AT91_PMC_CSS_SLOW (0 << 0) -#define AT91_PMC_CSS_MAIN (1 << 0) -#define AT91_PMC_CSS_PLLA (2 << 0) -#define AT91_PMC_CSS_PLLB (3 << 0) -#define AT91_PMC_CSS_UPLL (3 << 0) /* [some SAM9 only] */ -#define PMC_PRES_OFFSET 2 -#define AT91_PMC_PRES (7 << PMC_PRES_OFFSET) /* Master Clock Prescaler */ -#define AT91_PMC_PRES_1 (0 << PMC_PRES_OFFSET) -#define AT91_PMC_PRES_2 (1 << PMC_PRES_OFFSET) -#define AT91_PMC_PRES_4 (2 << PMC_PRES_OFFSET) -#define AT91_PMC_PRES_8 (3 << PMC_PRES_OFFSET) -#define AT91_PMC_PRES_16 (4 << PMC_PRES_OFFSET) -#define AT91_PMC_PRES_32 (5 << PMC_PRES_OFFSET) -#define AT91_PMC_PRES_64 (6 << PMC_PRES_OFFSET) -#define PMC_ALT_PRES_OFFSET 4 -#define AT91_PMC_ALT_PRES (7 << PMC_ALT_PRES_OFFSET) /* Master Clock Prescaler [alternate location] */ -#define AT91_PMC_ALT_PRES_1 (0 << PMC_ALT_PRES_OFFSET) -#define AT91_PMC_ALT_PRES_2 (1 << PMC_ALT_PRES_OFFSET) -#define AT91_PMC_ALT_PRES_4 (2 << PMC_ALT_PRES_OFFSET) -#define AT91_PMC_ALT_PRES_8 (3 << PMC_ALT_PRES_OFFSET) -#define AT91_PMC_ALT_PRES_16 (4 << PMC_ALT_PRES_OFFSET) -#define AT91_PMC_ALT_PRES_32 (5 << PMC_ALT_PRES_OFFSET) -#define AT91_PMC_ALT_PRES_64 (6 << PMC_ALT_PRES_OFFSET) -#define AT91_PMC_MDIV (3 << 8) /* Master Clock Division */ -#define AT91RM9200_PMC_MDIV_1 (0 << 8) /* [AT91RM9200 only] */ -#define AT91RM9200_PMC_MDIV_2 (1 << 8) -#define AT91RM9200_PMC_MDIV_3 (2 << 8) -#define AT91RM9200_PMC_MDIV_4 (3 << 8) -#define AT91SAM9_PMC_MDIV_1 (0 << 8) /* [SAM9 only] */ -#define AT91SAM9_PMC_MDIV_2 (1 << 8) -#define AT91SAM9_PMC_MDIV_4 (2 << 8) -#define AT91SAM9_PMC_MDIV_6 (3 << 8) /* [some SAM9 only] */ -#define AT91SAM9_PMC_MDIV_3 (3 << 8) /* [some SAM9 only] */ -#define AT91_PMC_PDIV (1 << 12) /* Processor Clock Division [some SAM9 only] */ -#define AT91_PMC_PDIV_1 (0 << 12) -#define AT91_PMC_PDIV_2 (1 << 12) -#define AT91_PMC_PLLADIV2 (1 << 12) /* PLLA divisor by 2 [some SAM9 only] */ -#define AT91_PMC_PLLADIV2_OFF (0 << 12) -#define AT91_PMC_PLLADIV2_ON (1 << 12) - -#define AT91_PMC_USB 0x38 /* USB Clock Register [some SAM9 only] */ -#define AT91_PMC_USBS (0x1 << 0) /* USB OHCI Input clock selection */ -#define AT91_PMC_USBS_PLLA (0 << 0) -#define AT91_PMC_USBS_UPLL (1 << 0) -#define AT91_PMC_USBS_PLLB (1 << 0) /* [AT91SAMN12 only] */ -#define AT91_PMC_OHCIUSBDIV (0xF << 8) /* Divider for USB OHCI Clock */ -#define AT91_PMC_OHCIUSBDIV_1 (0x0 << 8) -#define AT91_PMC_OHCIUSBDIV_2 (0x1 << 8) - -#define AT91_PMC_SMD 0x3c /* Soft Modem Clock Register [some SAM9 only] */ -#define AT91_PMC_SMDS (0x1 << 0) /* SMD input clock selection */ -#define AT91_PMC_SMD_DIV (0x1f << 8) /* SMD input clock divider */ -#define AT91_PMC_SMDDIV(n) (((n) << 8) & AT91_PMC_SMD_DIV) - -#define AT91_PMC_PCKR(n) (0x40 + ((n) * 4)) /* Programmable Clock 0-N Registers */ -#define AT91_PMC_ALT_PCKR_CSS (0x7 << 0) /* Programmable Clock Source Selection [alternate length] */ -#define AT91_PMC_CSS_MASTER (4 << 0) /* [some SAM9 only] */ -#define AT91_PMC_CSSMCK (0x1 << 8) /* CSS or Master Clock Selection */ -#define AT91_PMC_CSSMCK_CSS (0 << 8) -#define AT91_PMC_CSSMCK_MCK (1 << 8) - -#define AT91_PMC_IER 0x60 /* Interrupt Enable Register */ -#define AT91_PMC_IDR 0x64 /* Interrupt Disable Register */ -#define AT91_PMC_SR 0x68 /* Status Register */ -#define AT91_PMC_MOSCS (1 << 0) /* MOSCS Flag */ -#define AT91_PMC_LOCKA (1 << 1) /* PLLA Lock */ -#define AT91_PMC_LOCKB (1 << 2) /* PLLB Lock */ -#define AT91_PMC_MCKRDY (1 << 3) /* Master Clock */ -#define AT91_PMC_LOCKU (1 << 6) /* UPLL Lock [some SAM9] */ -#define AT91_PMC_PCK0RDY (1 << 8) /* Programmable Clock 0 */ -#define AT91_PMC_PCK1RDY (1 << 9) /* Programmable Clock 1 */ -#define AT91_PMC_PCK2RDY (1 << 10) /* Programmable Clock 2 */ -#define AT91_PMC_PCK3RDY (1 << 11) /* Programmable Clock 3 */ -#define AT91_PMC_MOSCSELS (1 << 16) /* Main Oscillator Selection [some SAM9] */ -#define AT91_PMC_MOSCRCS (1 << 17) /* Main On-Chip RC [some SAM9] */ -#define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */ -#define AT91_PMC_IMR 0x6c /* Interrupt Mask Register */ - -#define AT91_PMC_PROT 0xe4 /* Write Protect Mode Register [some SAM9] */ -#define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */ -#define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */ -#define AT91_PMC_PROTKEY (0x504d43 << 8) /* Activation Code */ - -#define AT91_PMC_WPSR 0xe8 /* Write Protect Status Register [some SAM9] */ -#define AT91_PMC_WPVS (0x1 << 0) /* Write Protect Violation Status */ -#define AT91_PMC_WPVSRC (0xffff << 8) /* Write Protect Violation Source */ - -#define AT91_PMC_PCER1 0x100 /* Peripheral Clock Enable Register 1 [SAMA5 only]*/ -#define AT91_PMC_PCDR1 0x104 /* Peripheral Clock Enable Register 1 */ -#define AT91_PMC_PCSR1 0x108 /* Peripheral Clock Enable Register 1 */ - -#define AT91_PMC_PCR 0x10c /* Peripheral Control Register [some SAM9 and SAMA5] */ -#define AT91_PMC_PCR_PID (0x3f << 0) /* Peripheral ID */ -#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ -#define AT91_PMC_PCR_DIV(n) ((n) << 16) /* Divisor Value */ -#define AT91_PMC_PCR_DIV0 0x0 /* Peripheral clock is MCK */ -#define AT91_PMC_PCR_DIV2 0x1 /* Peripheral clock is MCK/2 */ -#define AT91_PMC_PCR_DIV4 0x2 /* Peripheral clock is MCK/4 */ -#define AT91_PMC_PCR_DIV8 0x3 /* Peripheral clock is MCK/8 */ -#define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */ - -#endif diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 9986542e8060..d43b79f56e94 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -19,13 +19,13 @@ #include #include #include +#include #include #include #include #include -#include #include #include "at91_aic.h" diff --git a/arch/arm/mach-at91/pm_slowclock.S b/arch/arm/mach-at91/pm_slowclock.S index 098c28ddf025..20018779bae7 100644 --- a/arch/arm/mach-at91/pm_slowclock.S +++ b/arch/arm/mach-at91/pm_slowclock.S @@ -13,8 +13,8 @@ */ #include +#include #include -#include #include diff --git a/arch/arm/mach-at91/sama5d3.c b/arch/arm/mach-at91/sama5d3.c index 3ea86428ee09..5c6dc24fafbd 100644 --- a/arch/arm/mach-at91/sama5d3.c +++ b/arch/arm/mach-at91/sama5d3.c @@ -9,12 +9,12 @@ #include #include +#include #include #include #include #include -#include #include #include "soc.h" diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c index 094b3459c288..ca542dee087d 100644 --- a/arch/arm/mach-at91/setup.c +++ b/arch/arm/mach-at91/setup.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -18,7 +19,6 @@ #include #include #include -#include #include "at91_shdwc.h" #include "soc.h" diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 2cb52e0438df..9f71d9fdcc14 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -326,7 +326,7 @@ static int vbus_is_present(struct usba_udc *udc) #if defined(CONFIG_ARCH_AT91SAM9RL) -#include +#include static void toggle_bias(int is_on) { diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h new file mode 100644 index 000000000000..00c45b3510bf --- /dev/null +++ b/include/linux/clk/at91_pmc.h @@ -0,0 +1,190 @@ +/* + * include/linux/clk/at91_pmc.h + * + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) SAN People + * + * Power Management Controller (PMC) - System peripherals registers. + * Based on AT91RM9200 datasheet revision E. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef AT91_PMC_H +#define AT91_PMC_H + +#ifndef __ASSEMBLY__ +extern void __iomem *at91_pmc_base; + +#define at91_pmc_read(field) \ + __raw_readl(at91_pmc_base + field) + +#define at91_pmc_write(field, value) \ + __raw_writel(value, at91_pmc_base + field) +#else +.extern at91_pmc_base +#endif + +#define AT91_PMC_SCER 0x00 /* System Clock Enable Register */ +#define AT91_PMC_SCDR 0x04 /* System Clock Disable Register */ + +#define AT91_PMC_SCSR 0x08 /* System Clock Status Register */ +#define AT91_PMC_PCK (1 << 0) /* Processor Clock */ +#define AT91RM9200_PMC_UDP (1 << 1) /* USB Devcice Port Clock [AT91RM9200 only] */ +#define AT91RM9200_PMC_MCKUDP (1 << 2) /* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */ +#define AT91RM9200_PMC_UHP (1 << 4) /* USB Host Port Clock [AT91RM9200 only] */ +#define AT91SAM926x_PMC_UHP (1 << 6) /* USB Host Port Clock [AT91SAM926x only] */ +#define AT91SAM926x_PMC_UDP (1 << 7) /* USB Devcice Port Clock [AT91SAM926x only] */ +#define AT91_PMC_PCK0 (1 << 8) /* Programmable Clock 0 */ +#define AT91_PMC_PCK1 (1 << 9) /* Programmable Clock 1 */ +#define AT91_PMC_PCK2 (1 << 10) /* Programmable Clock 2 */ +#define AT91_PMC_PCK3 (1 << 11) /* Programmable Clock 3 */ +#define AT91_PMC_PCK4 (1 << 12) /* Programmable Clock 4 [AT572D940HF only] */ +#define AT91_PMC_HCK0 (1 << 16) /* AHB Clock (USB host) [AT91SAM9261 only] */ +#define AT91_PMC_HCK1 (1 << 17) /* AHB Clock (LCD) [AT91SAM9261 only] */ + +#define AT91_PMC_PCER 0x10 /* Peripheral Clock Enable Register */ +#define AT91_PMC_PCDR 0x14 /* Peripheral Clock Disable Register */ +#define AT91_PMC_PCSR 0x18 /* Peripheral Clock Status Register */ + +#define AT91_CKGR_UCKR 0x1C /* UTMI Clock Register [some SAM9] */ +#define AT91_PMC_UPLLEN (1 << 16) /* UTMI PLL Enable */ +#define AT91_PMC_UPLLCOUNT (0xf << 20) /* UTMI PLL Start-up Time */ +#define AT91_PMC_BIASEN (1 << 24) /* UTMI BIAS Enable */ +#define AT91_PMC_BIASCOUNT (0xf << 28) /* UTMI BIAS Start-up Time */ + +#define AT91_CKGR_MOR 0x20 /* Main Oscillator Register [not on SAM9RL] */ +#define AT91_PMC_MOSCEN (1 << 0) /* Main Oscillator Enable */ +#define AT91_PMC_OSCBYPASS (1 << 1) /* Oscillator Bypass */ +#define AT91_PMC_MOSCRCEN (1 << 3) /* Main On-Chip RC Oscillator Enable [some SAM9] */ +#define AT91_PMC_OSCOUNT (0xff << 8) /* Main Oscillator Start-up Time */ +#define AT91_PMC_KEY (0x37 << 16) /* MOR Writing Key */ +#define AT91_PMC_MOSCSEL (1 << 24) /* Main Oscillator Selection [some SAM9] */ +#define AT91_PMC_CFDEN (1 << 25) /* Clock Failure Detector Enable [some SAM9] */ + +#define AT91_CKGR_MCFR 0x24 /* Main Clock Frequency Register */ +#define AT91_PMC_MAINF (0xffff << 0) /* Main Clock Frequency */ +#define AT91_PMC_MAINRDY (1 << 16) /* Main Clock Ready */ + +#define AT91_CKGR_PLLAR 0x28 /* PLL A Register */ +#define AT91_CKGR_PLLBR 0x2c /* PLL B Register */ +#define AT91_PMC_DIV (0xff << 0) /* Divider */ +#define AT91_PMC_PLLCOUNT (0x3f << 8) /* PLL Counter */ +#define AT91_PMC_OUT (3 << 14) /* PLL Clock Frequency Range */ +#define AT91_PMC_MUL (0x7ff << 16) /* PLL Multiplier */ +#define AT91_PMC_MUL_GET(n) ((n) >> 16 & 0x7ff) +#define AT91_PMC3_MUL (0x7f << 18) /* PLL Multiplier [SAMA5 only] */ +#define AT91_PMC3_MUL_GET(n) ((n) >> 18 & 0x7f) +#define AT91_PMC_USBDIV (3 << 28) /* USB Divisor (PLLB only) */ +#define AT91_PMC_USBDIV_1 (0 << 28) +#define AT91_PMC_USBDIV_2 (1 << 28) +#define AT91_PMC_USBDIV_4 (2 << 28) +#define AT91_PMC_USB96M (1 << 28) /* Divider by 2 Enable (PLLB only) */ + +#define AT91_PMC_MCKR 0x30 /* Master Clock Register */ +#define AT91_PMC_CSS (3 << 0) /* Master Clock Selection */ +#define AT91_PMC_CSS_SLOW (0 << 0) +#define AT91_PMC_CSS_MAIN (1 << 0) +#define AT91_PMC_CSS_PLLA (2 << 0) +#define AT91_PMC_CSS_PLLB (3 << 0) +#define AT91_PMC_CSS_UPLL (3 << 0) /* [some SAM9 only] */ +#define PMC_PRES_OFFSET 2 +#define AT91_PMC_PRES (7 << PMC_PRES_OFFSET) /* Master Clock Prescaler */ +#define AT91_PMC_PRES_1 (0 << PMC_PRES_OFFSET) +#define AT91_PMC_PRES_2 (1 << PMC_PRES_OFFSET) +#define AT91_PMC_PRES_4 (2 << PMC_PRES_OFFSET) +#define AT91_PMC_PRES_8 (3 << PMC_PRES_OFFSET) +#define AT91_PMC_PRES_16 (4 << PMC_PRES_OFFSET) +#define AT91_PMC_PRES_32 (5 << PMC_PRES_OFFSET) +#define AT91_PMC_PRES_64 (6 << PMC_PRES_OFFSET) +#define PMC_ALT_PRES_OFFSET 4 +#define AT91_PMC_ALT_PRES (7 << PMC_ALT_PRES_OFFSET) /* Master Clock Prescaler [alternate location] */ +#define AT91_PMC_ALT_PRES_1 (0 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_ALT_PRES_2 (1 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_ALT_PRES_4 (2 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_ALT_PRES_8 (3 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_ALT_PRES_16 (4 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_ALT_PRES_32 (5 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_ALT_PRES_64 (6 << PMC_ALT_PRES_OFFSET) +#define AT91_PMC_MDIV (3 << 8) /* Master Clock Division */ +#define AT91RM9200_PMC_MDIV_1 (0 << 8) /* [AT91RM9200 only] */ +#define AT91RM9200_PMC_MDIV_2 (1 << 8) +#define AT91RM9200_PMC_MDIV_3 (2 << 8) +#define AT91RM9200_PMC_MDIV_4 (3 << 8) +#define AT91SAM9_PMC_MDIV_1 (0 << 8) /* [SAM9 only] */ +#define AT91SAM9_PMC_MDIV_2 (1 << 8) +#define AT91SAM9_PMC_MDIV_4 (2 << 8) +#define AT91SAM9_PMC_MDIV_6 (3 << 8) /* [some SAM9 only] */ +#define AT91SAM9_PMC_MDIV_3 (3 << 8) /* [some SAM9 only] */ +#define AT91_PMC_PDIV (1 << 12) /* Processor Clock Division [some SAM9 only] */ +#define AT91_PMC_PDIV_1 (0 << 12) +#define AT91_PMC_PDIV_2 (1 << 12) +#define AT91_PMC_PLLADIV2 (1 << 12) /* PLLA divisor by 2 [some SAM9 only] */ +#define AT91_PMC_PLLADIV2_OFF (0 << 12) +#define AT91_PMC_PLLADIV2_ON (1 << 12) + +#define AT91_PMC_USB 0x38 /* USB Clock Register [some SAM9 only] */ +#define AT91_PMC_USBS (0x1 << 0) /* USB OHCI Input clock selection */ +#define AT91_PMC_USBS_PLLA (0 << 0) +#define AT91_PMC_USBS_UPLL (1 << 0) +#define AT91_PMC_USBS_PLLB (1 << 0) /* [AT91SAMN12 only] */ +#define AT91_PMC_OHCIUSBDIV (0xF << 8) /* Divider for USB OHCI Clock */ +#define AT91_PMC_OHCIUSBDIV_1 (0x0 << 8) +#define AT91_PMC_OHCIUSBDIV_2 (0x1 << 8) + +#define AT91_PMC_SMD 0x3c /* Soft Modem Clock Register [some SAM9 only] */ +#define AT91_PMC_SMDS (0x1 << 0) /* SMD input clock selection */ +#define AT91_PMC_SMD_DIV (0x1f << 8) /* SMD input clock divider */ +#define AT91_PMC_SMDDIV(n) (((n) << 8) & AT91_PMC_SMD_DIV) + +#define AT91_PMC_PCKR(n) (0x40 + ((n) * 4)) /* Programmable Clock 0-N Registers */ +#define AT91_PMC_ALT_PCKR_CSS (0x7 << 0) /* Programmable Clock Source Selection [alternate length] */ +#define AT91_PMC_CSS_MASTER (4 << 0) /* [some SAM9 only] */ +#define AT91_PMC_CSSMCK (0x1 << 8) /* CSS or Master Clock Selection */ +#define AT91_PMC_CSSMCK_CSS (0 << 8) +#define AT91_PMC_CSSMCK_MCK (1 << 8) + +#define AT91_PMC_IER 0x60 /* Interrupt Enable Register */ +#define AT91_PMC_IDR 0x64 /* Interrupt Disable Register */ +#define AT91_PMC_SR 0x68 /* Status Register */ +#define AT91_PMC_MOSCS (1 << 0) /* MOSCS Flag */ +#define AT91_PMC_LOCKA (1 << 1) /* PLLA Lock */ +#define AT91_PMC_LOCKB (1 << 2) /* PLLB Lock */ +#define AT91_PMC_MCKRDY (1 << 3) /* Master Clock */ +#define AT91_PMC_LOCKU (1 << 6) /* UPLL Lock [some SAM9] */ +#define AT91_PMC_PCK0RDY (1 << 8) /* Programmable Clock 0 */ +#define AT91_PMC_PCK1RDY (1 << 9) /* Programmable Clock 1 */ +#define AT91_PMC_PCK2RDY (1 << 10) /* Programmable Clock 2 */ +#define AT91_PMC_PCK3RDY (1 << 11) /* Programmable Clock 3 */ +#define AT91_PMC_MOSCSELS (1 << 16) /* Main Oscillator Selection [some SAM9] */ +#define AT91_PMC_MOSCRCS (1 << 17) /* Main On-Chip RC [some SAM9] */ +#define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */ +#define AT91_PMC_IMR 0x6c /* Interrupt Mask Register */ + +#define AT91_PMC_PROT 0xe4 /* Write Protect Mode Register [some SAM9] */ +#define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */ +#define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */ +#define AT91_PMC_PROTKEY (0x504d43 << 8) /* Activation Code */ + +#define AT91_PMC_WPSR 0xe8 /* Write Protect Status Register [some SAM9] */ +#define AT91_PMC_WPVS (0x1 << 0) /* Write Protect Violation Status */ +#define AT91_PMC_WPVSRC (0xffff << 8) /* Write Protect Violation Source */ + +#define AT91_PMC_PCER1 0x100 /* Peripheral Clock Enable Register 1 [SAMA5 only]*/ +#define AT91_PMC_PCDR1 0x104 /* Peripheral Clock Enable Register 1 */ +#define AT91_PMC_PCSR1 0x108 /* Peripheral Clock Enable Register 1 */ + +#define AT91_PMC_PCR 0x10c /* Peripheral Control Register [some SAM9 and SAMA5] */ +#define AT91_PMC_PCR_PID (0x3f << 0) /* Peripheral ID */ +#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ +#define AT91_PMC_PCR_DIV(n) ((n) << 16) /* Divisor Value */ +#define AT91_PMC_PCR_DIV0 0x0 /* Peripheral clock is MCK */ +#define AT91_PMC_PCR_DIV2 0x1 /* Peripheral clock is MCK/2 */ +#define AT91_PMC_PCR_DIV4 0x2 /* Peripheral clock is MCK/4 */ +#define AT91_PMC_PCR_DIV8 0x3 /* Peripheral clock is MCK/8 */ +#define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */ + +#endif -- cgit v1.2.3-59-g8ed1b From 1a748d2bc5061b72588013a720645661345c0e65 Mon Sep 17 00:00:00 2001 From: Boris BREZILLON Date: Fri, 11 Oct 2013 10:48:26 +0200 Subject: clk: at91: add PMC pll clocks This patch adds new at91 pll clock implementation using common clk framework. The pll clock layout describe the PLLX register layout. There are four pll clock layouts: - at91rm9200 - at91sam9g20 - at91sam9g45 - sama5d3 PLL clocks are given characteristics: - min/max clock source rate - ranges of valid clock output rates - values to set in out and icpll fields for each supported output range These characteristics are checked during rate change to avoid over/underclocking. These characteristics are described in atmel's SoC datasheet in "Electrical Characteristics" paragraph. Signed-off-by: Boris BREZILLON Acked-by: Mike Turquette Signed-off-by: Nicolas Ferre --- drivers/clk/at91/Makefile | 2 +- drivers/clk/at91/clk-pll.c | 537 ++++++++++++++++++++++++++++++++++++++++++ drivers/clk/at91/clk-plldiv.c | 135 +++++++++++ drivers/clk/at91/pmc.c | 21 ++ drivers/clk/at91/pmc.h | 11 + include/linux/clk/at91_pmc.h | 2 + 6 files changed, 707 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/at91/clk-pll.c create mode 100644 drivers/clk/at91/clk-plldiv.c (limited to 'include/linux') diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 44105bd44aa1..902bbf1fe584 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -3,4 +3,4 @@ # obj-y += pmc.o -obj-y += clk-main.o +obj-y += clk-main.o clk-pll.o clk-plldiv.o diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c new file mode 100644 index 000000000000..5e23ee4ce387 --- /dev/null +++ b/drivers/clk/at91/clk-pll.c @@ -0,0 +1,537 @@ +/* + * Copyright (C) 2013 Boris BREZILLON + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define PLL_STATUS_MASK(id) (1 << (1 + (id))) +#define PLL_REG(id) (AT91_CKGR_PLLAR + ((id) * 4)) +#define PLL_DIV_MASK 0xff +#define PLL_DIV_MAX PLL_DIV_MASK +#define PLL_DIV(reg) ((reg) & PLL_DIV_MASK) +#define PLL_MUL(reg, layout) (((reg) >> (layout)->mul_shift) & \ + (layout)->mul_mask) +#define PLL_ICPR_SHIFT(id) ((id) * 16) +#define PLL_ICPR_MASK(id) (0xffff << PLL_ICPR_SHIFT(id)) +#define PLL_MAX_COUNT 0x3ff +#define PLL_COUNT_SHIFT 8 +#define PLL_OUT_SHIFT 14 +#define PLL_MAX_ID 1 + +struct clk_pll_characteristics { + struct clk_range input; + int num_output; + struct clk_range *output; + u16 *icpll; + u8 *out; +}; + +struct clk_pll_layout { + u32 pllr_mask; + u16 mul_mask; + u8 mul_shift; +}; + +#define to_clk_pll(hw) container_of(hw, struct clk_pll, hw) + +struct clk_pll { + struct clk_hw hw; + struct at91_pmc *pmc; + unsigned int irq; + wait_queue_head_t wait; + u8 id; + u8 div; + u8 range; + u16 mul; + const struct clk_pll_layout *layout; + const struct clk_pll_characteristics *characteristics; +}; + +static irqreturn_t clk_pll_irq_handler(int irq, void *dev_id) +{ + struct clk_pll *pll = (struct clk_pll *)dev_id; + + wake_up(&pll->wait); + disable_irq_nosync(pll->irq); + + return IRQ_HANDLED; +} + +static int clk_pll_prepare(struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + struct at91_pmc *pmc = pll->pmc; + const struct clk_pll_layout *layout = pll->layout; + u8 id = pll->id; + u32 mask = PLL_STATUS_MASK(id); + int offset = PLL_REG(id); + u8 out = 0; + u32 pllr, icpr; + u8 div; + u16 mul; + + pllr = pmc_read(pmc, offset); + div = PLL_DIV(pllr); + mul = PLL_MUL(pllr, layout); + + if ((pmc_read(pmc, AT91_PMC_SR) & mask) && + (div == pll->div && mul == pll->mul)) + return 0; + + if (characteristics->out) + out = characteristics->out[pll->range]; + if (characteristics->icpll) { + icpr = pmc_read(pmc, AT91_PMC_PLLICPR) & ~PLL_ICPR_MASK(id); + icpr |= (characteristics->icpll[pll->range] << + PLL_ICPR_SHIFT(id)); + pmc_write(pmc, AT91_PMC_PLLICPR, icpr); + } + + pllr &= ~layout->pllr_mask; + pllr |= layout->pllr_mask & + (pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) | + (out << PLL_OUT_SHIFT) | + ((pll->mul & layout->mul_mask) << layout->mul_shift)); + pmc_write(pmc, offset, pllr); + + while (!(pmc_read(pmc, AT91_PMC_SR) & mask)) { + enable_irq(pll->irq); + wait_event(pll->wait, + pmc_read(pmc, AT91_PMC_SR) & mask); + } + + return 0; +} + +static int clk_pll_is_prepared(struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + struct at91_pmc *pmc = pll->pmc; + + return !!(pmc_read(pmc, AT91_PMC_SR) & + PLL_STATUS_MASK(pll->id)); +} + +static void clk_pll_unprepare(struct clk_hw *hw) +{ + struct clk_pll *pll = to_clk_pll(hw); + struct at91_pmc *pmc = pll->pmc; + const struct clk_pll_layout *layout = pll->layout; + int offset = PLL_REG(pll->id); + u32 tmp = pmc_read(pmc, offset) & ~(layout->pllr_mask); + + pmc_write(pmc, offset, tmp); +} + +static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_pll *pll = to_clk_pll(hw); + const struct clk_pll_layout *layout = pll->layout; + struct at91_pmc *pmc = pll->pmc; + int offset = PLL_REG(pll->id); + u32 tmp = pmc_read(pmc, offset) & layout->pllr_mask; + u8 div = PLL_DIV(tmp); + u16 mul = PLL_MUL(tmp, layout); + if (!div || !mul) + return 0; + + return (parent_rate * (mul + 1)) / div; +} + +static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate, + unsigned long parent_rate, + u32 *div, u32 *mul, + u32 *index) { + unsigned long maxrate; + unsigned long minrate; + unsigned long divrate; + unsigned long bestdiv = 1; + unsigned long bestmul; + unsigned long tmpdiv; + unsigned long roundup; + unsigned long rounddown; + unsigned long remainder; + unsigned long bestremainder; + unsigned long maxmul; + unsigned long maxdiv; + unsigned long mindiv; + int i = 0; + const struct clk_pll_layout *layout = pll->layout; + const struct clk_pll_characteristics *characteristics = + pll->characteristics; + + /* Minimum divider = 1 */ + /* Maximum multiplier = max_mul */ + maxmul = layout->mul_mask + 1; + maxrate = (parent_rate * maxmul) / 1; + + /* Maximum divider = max_div */ + /* Minimum multiplier = 2 */ + maxdiv = PLL_DIV_MAX; + minrate = (parent_rate * 2) / maxdiv; + + if (parent_rate < characteristics->input.min || + parent_rate < characteristics->input.max) + return -ERANGE; + + if (parent_rate < minrate || parent_rate > maxrate) + return -ERANGE; + + for (i = 0; i < characteristics->num_output; i++) { + if (parent_rate >= characteristics->output[i].min && + parent_rate <= characteristics->output[i].max) + break; + } + + if (i >= characteristics->num_output) + return -ERANGE; + + bestmul = rate / parent_rate; + rounddown = parent_rate % rate; + roundup = rate - rounddown; + bestremainder = roundup < rounddown ? roundup : rounddown; + + if (!bestremainder) { + if (div) + *div = bestdiv; + if (mul) + *mul = bestmul; + if (index) + *index = i; + return rate; + } + + maxdiv = 255 / (bestmul + 1); + if (parent_rate / maxdiv < characteristics->input.min) + maxdiv = parent_rate / characteristics->input.min; + mindiv = parent_rate / characteristics->input.max; + if (parent_rate % characteristics->input.max) + mindiv++; + + for (tmpdiv = mindiv; tmpdiv < maxdiv; tmpdiv++) { + divrate = parent_rate / tmpdiv; + + rounddown = rate % divrate; + roundup = divrate - rounddown; + remainder = roundup < rounddown ? roundup : rounddown; + + if (remainder < bestremainder) { + bestremainder = remainder; + bestmul = rate / divrate; + bestdiv = tmpdiv; + } + + if (!remainder) + break; + } + + rate = (parent_rate / bestdiv) * bestmul; + + if (div) + *div = bestdiv; + if (mul) + *mul = bestmul; + if (index) + *index = i; + + return rate; +} + +static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk_pll *pll = to_clk_pll(hw); + + return clk_pll_get_best_div_mul(pll, rate, *parent_rate, + NULL, NULL, NULL); +} + +static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_pll *pll = to_clk_pll(hw); + struct at91_pmc *pmc = pll->pmc; + const struct clk_pll_layout *layout = pll->layout; + const struct clk_pll_characteristics *characteristics = + pll->characteristics; + u8 id = pll->id; + int offset = PLL_REG(id); + long ret; + u32 div; + u32 mul; + u32 index; + u32 tmp; + u8 out = 0; + + ret = clk_pll_get_best_div_mul(pll, rate, parent_rate, + &div, &mul, &index); + if (ret < 0) + return ret; + + pll->range = index; + pll->div = div; + pll->mul = mul; + + return 0; +} + +static const struct clk_ops pll_ops = { + .prepare = clk_pll_prepare, + .unprepare = clk_pll_unprepare, + .is_prepared = clk_pll_is_prepared, + .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_round_rate, + .set_rate = clk_pll_set_rate, +}; + +static struct clk * __init +at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name, + const char *parent_name, u8 id, + const struct clk_pll_layout *layout, + const struct clk_pll_characteristics *characteristics) +{ + struct clk_pll *pll; + struct clk *clk = NULL; + struct clk_init_data init; + int ret; + int offset = PLL_REG(id); + u32 tmp; + + if (id > PLL_MAX_ID) + return ERR_PTR(-EINVAL); + + pll = kzalloc(sizeof(*pll), GFP_KERNEL); + if (!pll) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &pll_ops; + init.parent_names = &parent_name; + init.num_parents = 1; + init.flags = CLK_SET_RATE_GATE; + + pll->id = id; + pll->hw.init = &init; + pll->layout = layout; + pll->characteristics = characteristics; + pll->pmc = pmc; + pll->irq = irq; + tmp = pmc_read(pmc, offset) & layout->pllr_mask; + pll->div = PLL_DIV(tmp); + pll->mul = PLL_MUL(tmp, layout); + init_waitqueue_head(&pll->wait); + irq_set_status_flags(pll->irq, IRQ_NOAUTOEN); + ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH, + id ? "clk-pllb" : "clk-plla", pll); + if (ret) + return ERR_PTR(ret); + + clk = clk_register(NULL, &pll->hw); + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} + + +static const struct clk_pll_layout at91rm9200_pll_layout = { + .pllr_mask = 0x7FFFFFF, + .mul_shift = 16, + .mul_mask = 0x7FF, +}; + +static const struct clk_pll_layout at91sam9g45_pll_layout = { + .pllr_mask = 0xFFFFFF, + .mul_shift = 16, + .mul_mask = 0xFF, +}; + +static const struct clk_pll_layout at91sam9g20_pllb_layout = { + .pllr_mask = 0x3FFFFF, + .mul_shift = 16, + .mul_mask = 0x3F, +}; + +static const struct clk_pll_layout sama5d3_pll_layout = { + .pllr_mask = 0x1FFFFFF, + .mul_shift = 18, + .mul_mask = 0x7F, +}; + + +static struct clk_pll_characteristics * __init +of_at91_clk_pll_get_characteristics(struct device_node *np) +{ + int i; + int offset; + u32 tmp; + int num_output; + u32 num_cells; + struct clk_range input; + struct clk_range *output; + u8 *out = NULL; + u16 *icpll = NULL; + struct clk_pll_characteristics *characteristics; + + if (of_at91_get_clk_range(np, "atmel,clk-input-range", &input)) + return NULL; + + if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells", + &num_cells)) + return NULL; + + if (num_cells < 2 || num_cells > 4) + return NULL; + + if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp)) + return NULL; + num_output = tmp / (sizeof(u32) * num_cells); + + characteristics = kzalloc(sizeof(*characteristics), GFP_KERNEL); + if (!characteristics) + return NULL; + + output = kzalloc(sizeof(*output) * num_output, GFP_KERNEL); + if (!output) + goto out_free_characteristics; + + if (num_cells > 2) { + out = kzalloc(sizeof(*out) * num_output, GFP_KERNEL); + if (!out) + goto out_free_output; + } + + if (num_cells > 3) { + icpll = kzalloc(sizeof(*icpll) * num_output, GFP_KERNEL); + if (!icpll) + goto out_free_output; + } + + for (i = 0; i < num_output; i++) { + offset = i * num_cells; + if (of_property_read_u32_index(np, + "atmel,pll-clk-output-ranges", + offset, &tmp)) + goto out_free_output; + output[i].min = tmp; + if (of_property_read_u32_index(np, + "atmel,pll-clk-output-ranges", + offset + 1, &tmp)) + goto out_free_output; + output[i].max = tmp; + + if (num_cells == 2) + continue; + + if (of_property_read_u32_index(np, + "atmel,pll-clk-output-ranges", + offset + 2, &tmp)) + goto out_free_output; + out[i] = tmp; + + if (num_cells == 3) + continue; + + if (of_property_read_u32_index(np, + "atmel,pll-clk-output-ranges", + offset + 3, &tmp)) + goto out_free_output; + icpll[i] = tmp; + } + + characteristics->input = input; + characteristics->num_output = num_output; + characteristics->output = output; + characteristics->out = out; + characteristics->icpll = icpll; + return characteristics; + +out_free_output: + kfree(icpll); + kfree(out); + kfree(output); +out_free_characteristics: + kfree(characteristics); + return NULL; +} + +static void __init +of_at91_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc, + const struct clk_pll_layout *layout) +{ + u32 id; + unsigned int irq; + struct clk *clk; + const char *parent_name; + const char *name = np->name; + struct clk_pll_characteristics *characteristics; + + if (of_property_read_u32(np, "reg", &id)) + return; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + + characteristics = of_at91_clk_pll_get_characteristics(np); + if (!characteristics) + return; + + irq = irq_of_parse_and_map(np, 0); + if (!irq) + return; + + clk = at91_clk_register_pll(pmc, irq, name, parent_name, id, layout, + characteristics); + if (IS_ERR(clk)) + goto out_free_characteristics; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; + +out_free_characteristics: + kfree(characteristics); +} + +void __init of_at91rm9200_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_pll_setup(np, pmc, &at91rm9200_pll_layout); +} + +void __init of_at91sam9g45_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_pll_setup(np, pmc, &at91sam9g45_pll_layout); +} + +void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_pll_setup(np, pmc, &at91sam9g20_pllb_layout); +} + +void __init of_sama5d3_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_pll_setup(np, pmc, &sama5d3_pll_layout); +} diff --git a/drivers/clk/at91/clk-plldiv.c b/drivers/clk/at91/clk-plldiv.c new file mode 100644 index 000000000000..ea226562bb40 --- /dev/null +++ b/drivers/clk/at91/clk-plldiv.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2013 Boris BREZILLON + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define to_clk_plldiv(hw) container_of(hw, struct clk_plldiv, hw) + +struct clk_plldiv { + struct clk_hw hw; + struct at91_pmc *pmc; +}; + +static unsigned long clk_plldiv_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_plldiv *plldiv = to_clk_plldiv(hw); + struct at91_pmc *pmc = plldiv->pmc; + + if (pmc_read(pmc, AT91_PMC_MCKR) & AT91_PMC_PLLADIV2) + return parent_rate / 2; + + return parent_rate; +} + +static long clk_plldiv_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long div; + + if (rate > *parent_rate) + return *parent_rate; + div = *parent_rate / 2; + if (rate < div) + return div; + + if (rate - div < *parent_rate - rate) + return div; + + return *parent_rate; +} + +static int clk_plldiv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_plldiv *plldiv = to_clk_plldiv(hw); + struct at91_pmc *pmc = plldiv->pmc; + u32 tmp; + + if (parent_rate != rate && (parent_rate / 2) != rate) + return -EINVAL; + + pmc_lock(pmc); + tmp = pmc_read(pmc, AT91_PMC_MCKR) & ~AT91_PMC_PLLADIV2; + if ((parent_rate / 2) == rate) + tmp |= AT91_PMC_PLLADIV2; + pmc_write(pmc, AT91_PMC_MCKR, tmp); + pmc_unlock(pmc); + + return 0; +} + +static const struct clk_ops plldiv_ops = { + .recalc_rate = clk_plldiv_recalc_rate, + .round_rate = clk_plldiv_round_rate, + .set_rate = clk_plldiv_set_rate, +}; + +static struct clk * __init +at91_clk_register_plldiv(struct at91_pmc *pmc, const char *name, + const char *parent_name) +{ + struct clk_plldiv *plldiv; + struct clk *clk = NULL; + struct clk_init_data init; + + plldiv = kzalloc(sizeof(*plldiv), GFP_KERNEL); + if (!plldiv) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &plldiv_ops; + init.parent_names = parent_name ? &parent_name : NULL; + init.num_parents = parent_name ? 1 : 0; + init.flags = CLK_SET_RATE_GATE; + + plldiv->hw.init = &init; + plldiv->pmc = pmc; + + clk = clk_register(NULL, &plldiv->hw); + + if (IS_ERR(clk)) + kfree(plldiv); + + return clk; +} + +static void __init +of_at91_clk_plldiv_setup(struct device_node *np, struct at91_pmc *pmc) +{ + struct clk *clk; + const char *parent_name; + const char *name = np->name; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + + clk = at91_clk_register_plldiv(pmc, name, parent_name); + + if (IS_ERR(clk)) + return; + + of_clk_add_provider(np, of_clk_src_simple_get, clk); + return; +} + +void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + of_at91_clk_plldiv_setup(np, pmc); +} diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 3d35b7313868..5af3f2fbf45e 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -234,6 +234,27 @@ static const struct of_device_id pmc_clk_ids[] __initdata = { .compatible = "atmel,at91rm9200-clk-main", .data = of_at91rm9200_clk_main_setup, }, + /* PLL clocks */ + { + .compatible = "atmel,at91rm9200-clk-pll", + .data = of_at91rm9200_clk_pll_setup, + }, + { + .compatible = "atmel,at91sam9g45-clk-pll", + .data = of_at91sam9g45_clk_pll_setup, + }, + { + .compatible = "atmel,at91sam9g20-clk-pllb", + .data = of_at91sam9g20_clk_pllb_setup, + }, + { + .compatible = "atmel,sama5d3-clk-pll", + .data = of_sama5d3_clk_pll_setup, + }, + { + .compatible = "atmel,at91sam9x5-clk-plldiv", + .data = of_at91sam9x5_clk_plldiv_setup, + }, { /*sentinel*/ } }; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index 729aa46c7289..15aaf38e37c5 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -61,4 +61,15 @@ int of_at91_get_clk_range(struct device_node *np, const char *propname, extern void __init of_at91rm9200_clk_main_setup(struct device_node *np, struct at91_pmc *pmc); +extern void __init of_at91rm9200_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_at91sam9g45_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_at91sam9g20_clk_pllb_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_sama5d3_clk_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np, + struct at91_pmc *pmc); + #endif /* __PMC_H_ */ diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index 00c45b3510bf..a6911ebbd02a 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -164,6 +164,8 @@ extern void __iomem *at91_pmc_base; #define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */ #define AT91_PMC_IMR 0x6c /* Interrupt Mask Register */ +#define AT91_PMC_PLLICPR 0x80 /* PLL Charge Pump Current Register */ + #define AT91_PMC_PROT 0xe4 /* Write Protect Mode Register [some SAM9] */ #define AT91_PMC_WPEN (0x1 << 0) /* Write Protect Enable */ #define AT91_PMC_WPKEY (0xffffff << 8) /* Write Protect Key */ -- cgit v1.2.3-59-g8ed1b From 2621bca83a4774854234c1c1c6d8c1ca2fd5e08a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 2 Dec 2013 15:15:37 +0530 Subject: tracepoint: comment fix "binay" -> "binary" Binary was written as binay, probably by mistake. Fix it. Signed-off-by: Viresh Kumar Acked-by: Steven Rostedt Signed-off-by: Jiri Kosina --- include/linux/tracepoint.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index ebeab360d851..f0c3e4cb45a8 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -274,7 +274,7 @@ static inline void tracepoint_synchronize_unregister(void) * For use with the TRACE_EVENT macro: * * We define a tracepoint, its arguments, its printk format - * and its 'fast binay record' layout. + * and its 'fast binary record' layout. * * Firstly, name your tracepoint via TRACE_EVENT(name : the * 'subsystem_event' notation is fine. -- cgit v1.2.3-59-g8ed1b From e8fcaa5c54e3b0371230e5d43a6f650c667da9c5 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 7 Aug 2013 22:28:01 +0200 Subject: nohz: Convert a few places to use local per cpu accesses A few functions use remote per CPU access APIs when they deal with local values. Just do the right conversion to improve performance, code readability and debug checks. While at it, lets extend some of these function names with *_this_cpu() suffix in order to display their purpose more clearly. Signed-off-by: Frederic Weisbecker Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Oleg Nesterov Cc: Steven Rostedt --- include/linux/tick.h | 6 +++--- kernel/softirq.c | 4 +--- kernel/time/tick-broadcast.c | 6 +++--- kernel/time/tick-internal.h | 4 ++-- kernel/time/tick-sched.c | 39 ++++++++++++++++----------------------- 5 files changed, 25 insertions(+), 34 deletions(-) (limited to 'include/linux') diff --git a/include/linux/tick.h b/include/linux/tick.h index 5128d33bbb39..a004f66a6cf0 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -104,7 +104,7 @@ extern struct cpumask *tick_get_broadcast_oneshot_mask(void); extern void tick_clock_notify(void); extern int tick_check_oneshot_change(int allow_nohz); extern struct tick_sched *tick_get_tick_sched(int cpu); -extern void tick_check_idle(int cpu); +extern void tick_check_idle(void); extern int tick_oneshot_mode_active(void); # ifndef arch_needs_cpu # define arch_needs_cpu(cpu) (0) @@ -112,7 +112,7 @@ extern int tick_oneshot_mode_active(void); # else static inline void tick_clock_notify(void) { } static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } -static inline void tick_check_idle(int cpu) { } +static inline void tick_check_idle(void) { } static inline int tick_oneshot_mode_active(void) { return 0; } # endif @@ -121,7 +121,7 @@ static inline void tick_init(void) { } static inline void tick_cancel_sched_timer(int cpu) { } static inline void tick_clock_notify(void) { } static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } -static inline void tick_check_idle(int cpu) { } +static inline void tick_check_idle(void) { } static inline int tick_oneshot_mode_active(void) { return 0; } #endif /* !CONFIG_GENERIC_CLOCKEVENTS */ diff --git a/kernel/softirq.c b/kernel/softirq.c index 11025ccc06dd..11348de09400 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -311,8 +311,6 @@ asmlinkage void do_softirq(void) */ void irq_enter(void) { - int cpu = smp_processor_id(); - rcu_irq_enter(); if (is_idle_task(current) && !in_interrupt()) { /* @@ -320,7 +318,7 @@ void irq_enter(void) * here, as softirq will be serviced on return from interrupt. */ local_bh_disable(); - tick_check_idle(cpu); + tick_check_idle(); _local_bh_enable(); } diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c index 9532690daaa9..43780ab5e279 100644 --- a/kernel/time/tick-broadcast.c +++ b/kernel/time/tick-broadcast.c @@ -538,10 +538,10 @@ int tick_resume_broadcast_oneshot(struct clock_event_device *bc) * Called from irq_enter() when idle was interrupted to reenable the * per cpu device. */ -void tick_check_oneshot_broadcast(int cpu) +void tick_check_oneshot_broadcast_this_cpu(void) { - if (cpumask_test_cpu(cpu, tick_broadcast_oneshot_mask)) { - struct tick_device *td = &per_cpu(tick_cpu_device, cpu); + if (cpumask_test_cpu(smp_processor_id(), tick_broadcast_oneshot_mask)) { + struct tick_device *td = &__get_cpu_var(tick_cpu_device); /* * We might be in the middle of switching over from diff --git a/kernel/time/tick-internal.h b/kernel/time/tick-internal.h index 18e71f7fbc2a..e2bced59b6dd 100644 --- a/kernel/time/tick-internal.h +++ b/kernel/time/tick-internal.h @@ -51,7 +51,7 @@ extern void tick_broadcast_switch_to_oneshot(void); extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup); extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc); extern int tick_broadcast_oneshot_active(void); -extern void tick_check_oneshot_broadcast(int cpu); +extern void tick_check_oneshot_broadcast_this_cpu(void); bool tick_broadcast_oneshot_available(void); # else /* BROADCAST */ static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) @@ -62,7 +62,7 @@ static inline void tick_broadcast_oneshot_control(unsigned long reason) { } static inline void tick_broadcast_switch_to_oneshot(void) { } static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { } static inline int tick_broadcast_oneshot_active(void) { return 0; } -static inline void tick_check_oneshot_broadcast(int cpu) { } +static inline void tick_check_oneshot_broadcast_this_cpu(void) { } static inline bool tick_broadcast_oneshot_available(void) { return true; } # endif /* !BROADCAST */ diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 3612fc77f834..2afd43fca93b 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -391,11 +391,9 @@ __setup("nohz=", setup_tick_nohz); */ static void tick_nohz_update_jiffies(ktime_t now) { - int cpu = smp_processor_id(); - struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); unsigned long flags; - ts->idle_waketime = now; + __this_cpu_write(tick_cpu_sched.idle_waketime, now); local_irq_save(flags); tick_do_update_jiffies64(now); @@ -426,17 +424,15 @@ update_ts_time_stats(int cpu, struct tick_sched *ts, ktime_t now, u64 *last_upda } -static void tick_nohz_stop_idle(int cpu, ktime_t now) +static void tick_nohz_stop_idle(struct tick_sched *ts, ktime_t now) { - struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); - - update_ts_time_stats(cpu, ts, now, NULL); + update_ts_time_stats(smp_processor_id(), ts, now, NULL); ts->idle_active = 0; sched_clock_idle_wakeup_event(0); } -static ktime_t tick_nohz_start_idle(int cpu, struct tick_sched *ts) +static ktime_t tick_nohz_start_idle(struct tick_sched *ts) { ktime_t now = ktime_get(); @@ -752,7 +748,7 @@ static void __tick_nohz_idle_enter(struct tick_sched *ts) ktime_t now, expires; int cpu = smp_processor_id(); - now = tick_nohz_start_idle(cpu, ts); + now = tick_nohz_start_idle(ts); if (can_stop_idle_tick(cpu, ts)) { int was_stopped = ts->tick_stopped; @@ -914,8 +910,7 @@ static void tick_nohz_account_idle_ticks(struct tick_sched *ts) */ void tick_nohz_idle_exit(void) { - int cpu = smp_processor_id(); - struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); + struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); ktime_t now; local_irq_disable(); @@ -928,7 +923,7 @@ void tick_nohz_idle_exit(void) now = ktime_get(); if (ts->idle_active) - tick_nohz_stop_idle(cpu, now); + tick_nohz_stop_idle(ts, now); if (ts->tick_stopped) { tick_nohz_restart_sched_tick(ts, now); @@ -1012,12 +1007,10 @@ static void tick_nohz_switch_to_nohz(void) * timer and do not touch the other magic bits which need to be done * when idle is left. */ -static void tick_nohz_kick_tick(int cpu, ktime_t now) +static void tick_nohz_kick_tick(struct tick_sched *ts, ktime_t now) { #if 0 /* Switch back to 2.6.27 behaviour */ - - struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); ktime_t delta; /* @@ -1032,36 +1025,36 @@ static void tick_nohz_kick_tick(int cpu, ktime_t now) #endif } -static inline void tick_check_nohz(int cpu) +static inline void tick_check_nohz_this_cpu(void) { - struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); + struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched); ktime_t now; if (!ts->idle_active && !ts->tick_stopped) return; now = ktime_get(); if (ts->idle_active) - tick_nohz_stop_idle(cpu, now); + tick_nohz_stop_idle(ts, now); if (ts->tick_stopped) { tick_nohz_update_jiffies(now); - tick_nohz_kick_tick(cpu, now); + tick_nohz_kick_tick(ts, now); } } #else static inline void tick_nohz_switch_to_nohz(void) { } -static inline void tick_check_nohz(int cpu) { } +static inline void tick_check_nohz_this_cpu(void) { } #endif /* CONFIG_NO_HZ_COMMON */ /* * Called from irq_enter to notify about the possible interruption of idle() */ -void tick_check_idle(int cpu) +void tick_check_idle(void) { - tick_check_oneshot_broadcast(cpu); - tick_check_nohz(cpu); + tick_check_oneshot_broadcast_this_cpu(); + tick_check_nohz_this_cpu(); } /* -- cgit v1.2.3-59-g8ed1b From 58135f574f1b791c926622387780ed3d090116d6 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 6 Nov 2013 14:45:57 +0100 Subject: context_tracking: Wrap static key check into more intuitive function name Use a function with a meaningful name to check the global context tracking state. static_key_false() is a bit confusing for reviewers. Signed-off-by: Frederic Weisbecker Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Oleg Nesterov Cc: Steven Rostedt --- include/linux/context_tracking.h | 10 +++++----- include/linux/context_tracking_state.h | 4 ++++ include/linux/tick.h | 2 +- include/linux/vtime.h | 2 +- kernel/context_tracking.c | 8 ++++---- 5 files changed, 15 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/include/linux/context_tracking.h b/include/linux/context_tracking.h index 158158704c30..37b81bd51ec0 100644 --- a/include/linux/context_tracking.h +++ b/include/linux/context_tracking.h @@ -17,13 +17,13 @@ extern void __context_tracking_task_switch(struct task_struct *prev, static inline void user_enter(void) { - if (static_key_false(&context_tracking_enabled)) + if (context_tracking_is_enabled()) context_tracking_user_enter(); } static inline void user_exit(void) { - if (static_key_false(&context_tracking_enabled)) + if (context_tracking_is_enabled()) context_tracking_user_exit(); } @@ -31,7 +31,7 @@ static inline enum ctx_state exception_enter(void) { enum ctx_state prev_ctx; - if (!static_key_false(&context_tracking_enabled)) + if (!context_tracking_is_enabled()) return 0; prev_ctx = this_cpu_read(context_tracking.state); @@ -42,7 +42,7 @@ static inline enum ctx_state exception_enter(void) static inline void exception_exit(enum ctx_state prev_ctx) { - if (static_key_false(&context_tracking_enabled)) { + if (context_tracking_is_enabled()) { if (prev_ctx == IN_USER) context_tracking_user_enter(); } @@ -51,7 +51,7 @@ static inline void exception_exit(enum ctx_state prev_ctx) static inline void context_tracking_task_switch(struct task_struct *prev, struct task_struct *next) { - if (static_key_false(&context_tracking_enabled)) + if (context_tracking_is_enabled()) __context_tracking_task_switch(prev, next); } #else diff --git a/include/linux/context_tracking_state.h b/include/linux/context_tracking_state.h index 0f1979d0674f..0db535b79be7 100644 --- a/include/linux/context_tracking_state.h +++ b/include/linux/context_tracking_state.h @@ -22,6 +22,10 @@ struct context_tracking { extern struct static_key context_tracking_enabled; DECLARE_PER_CPU(struct context_tracking, context_tracking); +static inline bool context_tracking_is_enabled(void) +{ + return static_key_false(&context_tracking_enabled); +} static inline bool context_tracking_in_user(void) { return __this_cpu_read(context_tracking.state) == IN_USER; diff --git a/include/linux/tick.h b/include/linux/tick.h index a004f66a6cf0..0175d8663b6c 100644 --- a/include/linux/tick.h +++ b/include/linux/tick.h @@ -165,7 +165,7 @@ extern cpumask_var_t tick_nohz_full_mask; static inline bool tick_nohz_full_enabled(void) { - if (!static_key_false(&context_tracking_enabled)) + if (!context_tracking_is_enabled()) return false; return tick_nohz_full_running; diff --git a/include/linux/vtime.h b/include/linux/vtime.h index f5b72b364bda..807c732cbf29 100644 --- a/include/linux/vtime.h +++ b/include/linux/vtime.h @@ -19,7 +19,7 @@ static inline bool vtime_accounting_enabled(void) { return true; } #ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN static inline bool vtime_accounting_enabled(void) { - if (static_key_false(&context_tracking_enabled)) { + if (context_tracking_is_enabled()) { if (context_tracking_active()) return true; } diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c index e5f3917aa05b..6cb20d2e7ee0 100644 --- a/kernel/context_tracking.c +++ b/kernel/context_tracking.c @@ -53,10 +53,10 @@ void context_tracking_user_enter(void) /* * Repeat the user_enter() check here because some archs may be calling * this from asm and if no CPU needs context tracking, they shouldn't - * go further. Repeat the check here until they support the static key - * check. + * go further. Repeat the check here until they support the inline static + * key check. */ - if (!static_key_false(&context_tracking_enabled)) + if (!context_tracking_is_enabled()) return; /* @@ -160,7 +160,7 @@ void context_tracking_user_exit(void) { unsigned long flags; - if (!static_key_false(&context_tracking_enabled)) + if (!context_tracking_is_enabled()) return; if (in_interrupt()) -- cgit v1.2.3-59-g8ed1b From d0df09ebfc126b23c1005f98ddecc9907f9c5d25 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 6 Nov 2013 15:11:57 +0100 Subject: context_tracking: Rename context_tracking_active() to context_tracking_cpu_is_enabled() We currently have a confusing couple of API naming with the existing context_tracking_active() and context_tracking_is_enabled(). Lets keep the latter one, context_tracking_is_enabled(), for global context tracking state check and use context_tracking_cpu_is_enabled() for local state check. Signed-off-by: Frederic Weisbecker Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Oleg Nesterov Cc: Steven Rostedt --- include/linux/context_tracking_state.h | 9 +++++---- include/linux/vtime.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/context_tracking_state.h b/include/linux/context_tracking_state.h index 0db535b79be7..97a81225d037 100644 --- a/include/linux/context_tracking_state.h +++ b/include/linux/context_tracking_state.h @@ -26,14 +26,15 @@ static inline bool context_tracking_is_enabled(void) { return static_key_false(&context_tracking_enabled); } -static inline bool context_tracking_in_user(void) + +static inline bool context_tracking_cpu_is_enabled(void) { - return __this_cpu_read(context_tracking.state) == IN_USER; + return __this_cpu_read(context_tracking.active); } -static inline bool context_tracking_active(void) +static inline bool context_tracking_in_user(void) { - return __this_cpu_read(context_tracking.active); + return __this_cpu_read(context_tracking.state) == IN_USER; } #else static inline bool context_tracking_in_user(void) { return false; } diff --git a/include/linux/vtime.h b/include/linux/vtime.h index 807c732cbf29..c5165fd256f9 100644 --- a/include/linux/vtime.h +++ b/include/linux/vtime.h @@ -20,7 +20,7 @@ static inline bool vtime_accounting_enabled(void) { return true; } static inline bool vtime_accounting_enabled(void) { if (context_tracking_is_enabled()) { - if (context_tracking_active()) + if (context_tracking_cpu_is_enabled()) return true; } -- cgit v1.2.3-59-g8ed1b From e9c9489f1077880cb8332f3e1600bf8edba3e86a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 25 Nov 2013 15:43:37 +0100 Subject: pinctrl: provide documentation pointer The PIN_CONFIG_OUTPUT parameter is really tricky to understand and needs an explicit pointer to the documentation. Cc: Tomasz Figa Cc: Kyungmin Park Signed-off-by: Linus Walleij --- include/linux/pinctrl/pinconf-generic.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index fb90ef5eb038..282309d7c4dc 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -82,8 +82,10 @@ * operation, if several modes of operation are supported these can be * passed in the argument on a custom form, else just use argument 1 * to indicate low power mode, argument 0 turns low power mode off. - * @PIN_CONFIG_OUTPUT: this will configure the pin in output, use argument - * 1 to indicate high level, argument 0 to indicate low level. + * @PIN_CONFIG_OUTPUT: this will configure the pin as an output. Use argument + * 1 to indicate high level, argument 0 to indicate low level. (Please + * see Documentation/pinctrl.txt, section "GPIO mode pitfalls" for a + * discussion around this parameter.) * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if * you need to pass in custom configurations to the pin controller, use * PIN_CONFIG_END+1 as the base offset. -- cgit v1.2.3-59-g8ed1b From eef80f333fe659b2a5782abcaae93848d3963b57 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 21 Nov 2013 13:55:14 +0100 Subject: ARM: lpc32xx: move custom GPIO header Move to . Acked-by: Roland Stigge Signed-off-by: Linus Walleij --- arch/arm/mach-lpc32xx/include/mach/gpio-lpc32xx.h | 50 ----------------------- arch/arm/mach-lpc32xx/phy3250.c | 2 +- drivers/gpio/gpio-lpc32xx.c | 2 +- include/linux/platform_data/gpio-lpc32xx.h | 50 +++++++++++++++++++++++ 4 files changed, 52 insertions(+), 52 deletions(-) delete mode 100644 arch/arm/mach-lpc32xx/include/mach/gpio-lpc32xx.h create mode 100644 include/linux/platform_data/gpio-lpc32xx.h (limited to 'include/linux') diff --git a/arch/arm/mach-lpc32xx/include/mach/gpio-lpc32xx.h b/arch/arm/mach-lpc32xx/include/mach/gpio-lpc32xx.h deleted file mode 100644 index a544e962a818..000000000000 --- a/arch/arm/mach-lpc32xx/include/mach/gpio-lpc32xx.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Author: Kevin Wells - * - * Copyright (C) 2010 NXP Semiconductors - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef __MACH_GPIO_LPC32XX_H -#define __MACH_GPIO_LPC32XX_H - -/* - * Note! - * Muxed GP pins need to be setup to the GP state in the board level - * code prior to using this driver. - * GPI pins : 28xP3 group - * GPO pins : 24xP3 group - * GPIO pins: 8xP0 group, 24xP1 group, 13xP2 group, 6xP3 group - */ - -#define LPC32XX_GPIO_P0_MAX 8 -#define LPC32XX_GPIO_P1_MAX 24 -#define LPC32XX_GPIO_P2_MAX 13 -#define LPC32XX_GPIO_P3_MAX 6 -#define LPC32XX_GPI_P3_MAX 29 -#define LPC32XX_GPO_P3_MAX 24 - -#define LPC32XX_GPIO_P0_GRP 0 -#define LPC32XX_GPIO_P1_GRP (LPC32XX_GPIO_P0_GRP + LPC32XX_GPIO_P0_MAX) -#define LPC32XX_GPIO_P2_GRP (LPC32XX_GPIO_P1_GRP + LPC32XX_GPIO_P1_MAX) -#define LPC32XX_GPIO_P3_GRP (LPC32XX_GPIO_P2_GRP + LPC32XX_GPIO_P2_MAX) -#define LPC32XX_GPI_P3_GRP (LPC32XX_GPIO_P3_GRP + LPC32XX_GPIO_P3_MAX) -#define LPC32XX_GPO_P3_GRP (LPC32XX_GPI_P3_GRP + LPC32XX_GPI_P3_MAX) - -/* - * A specific GPIO can be selected with this macro - * ie, GPIO_05 can be selected with LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5) - * See the LPC32x0 User's guide for GPIO group numbers - */ -#define LPC32XX_GPIO(x, y) ((x) + (y)) - -#endif /* __MACH_GPIO_LPC32XX_H */ diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c index e54f87ec2e4a..34932e0e31fa 100644 --- a/arch/arm/mach-lpc32xx/phy3250.c +++ b/arch/arm/mach-lpc32xx/phy3250.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,6 @@ #include #include #include -#include #include "common.h" /* diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index 2d5555decf0c..a7093e010149 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -25,10 +25,10 @@ #include #include #include +#include #include #include -#include #include #define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000) diff --git a/include/linux/platform_data/gpio-lpc32xx.h b/include/linux/platform_data/gpio-lpc32xx.h new file mode 100644 index 000000000000..a544e962a818 --- /dev/null +++ b/include/linux/platform_data/gpio-lpc32xx.h @@ -0,0 +1,50 @@ +/* + * Author: Kevin Wells + * + * Copyright (C) 2010 NXP Semiconductors + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MACH_GPIO_LPC32XX_H +#define __MACH_GPIO_LPC32XX_H + +/* + * Note! + * Muxed GP pins need to be setup to the GP state in the board level + * code prior to using this driver. + * GPI pins : 28xP3 group + * GPO pins : 24xP3 group + * GPIO pins: 8xP0 group, 24xP1 group, 13xP2 group, 6xP3 group + */ + +#define LPC32XX_GPIO_P0_MAX 8 +#define LPC32XX_GPIO_P1_MAX 24 +#define LPC32XX_GPIO_P2_MAX 13 +#define LPC32XX_GPIO_P3_MAX 6 +#define LPC32XX_GPI_P3_MAX 29 +#define LPC32XX_GPO_P3_MAX 24 + +#define LPC32XX_GPIO_P0_GRP 0 +#define LPC32XX_GPIO_P1_GRP (LPC32XX_GPIO_P0_GRP + LPC32XX_GPIO_P0_MAX) +#define LPC32XX_GPIO_P2_GRP (LPC32XX_GPIO_P1_GRP + LPC32XX_GPIO_P1_MAX) +#define LPC32XX_GPIO_P3_GRP (LPC32XX_GPIO_P2_GRP + LPC32XX_GPIO_P2_MAX) +#define LPC32XX_GPI_P3_GRP (LPC32XX_GPIO_P3_GRP + LPC32XX_GPIO_P3_MAX) +#define LPC32XX_GPO_P3_GRP (LPC32XX_GPI_P3_GRP + LPC32XX_GPI_P3_MAX) + +/* + * A specific GPIO can be selected with this macro + * ie, GPIO_05 can be selected with LPC32XX_GPIO(LPC32XX_GPIO_P3_GRP, 5) + * See the LPC32x0 User's guide for GPIO group numbers + */ +#define LPC32XX_GPIO(x, y) ((x) + (y)) + +#endif /* __MACH_GPIO_LPC32XX_H */ -- cgit v1.2.3-59-g8ed1b From 978f47d64365fa1659178e54c5106154c315b595 Mon Sep 17 00:00:00 2001 From: Martyn Welch Date: Fri, 8 Nov 2013 11:58:34 +0000 Subject: VME: Provide access to VME bus enumeration and fix vme_user match function The match function for vme_user is completely wrong. It will blindly bind against the first VME slot on each bus (at this point that would be just the first bus as the driver can only handle one bus). The original intention (before some major subsystem changes) was that the driver bind against the slot to which the bridge was attached in the VME system and to the bus(es) provided via the "bus" module parameter. To do this cleanly (i.e. without poking arround in the subsystems internal stuctures) a functionality has been added to provide access to the bus enumeration. Signed-off-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- Documentation/vme_api.txt | 10 ++++++++++ drivers/staging/vme/devices/vme_user.c | 13 ++++++++++--- drivers/vme/vme.c | 13 +++++++++++++ include/linux/vme.h | 1 + 4 files changed, 34 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/Documentation/vme_api.txt b/Documentation/vme_api.txt index 856efa35f6e3..126a1f1d5151 100644 --- a/Documentation/vme_api.txt +++ b/Documentation/vme_api.txt @@ -394,3 +394,13 @@ Slot Detection This function returns the slot ID of the provided bridge. int vme_slot_get(struct vme_dev *dev); + + +Bus Detection +============= + +This function returns the bus ID of the provided bridge. + + int vme_bus_num(struct vme_dev *dev); + + diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index daec15565a43..caee906f9b38 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -663,9 +663,16 @@ err_nocard: static int vme_user_match(struct vme_dev *vdev) { - if (vdev->num >= VME_USER_BUS_MAX) - return 0; - return 1; + int i; + + int cur_bus = vme_bus_num(vdev); + int cur_slot = vme_slot_get(vdev); + + for (i = 0; i < bus_num; i++) + if ((cur_bus == bus[i]) && (cur_slot == vdev->num)) + return 1; + + return 0; } /* diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c index f6856b427496..8df5e4efc1ca 100644 --- a/drivers/vme/vme.c +++ b/drivers/vme/vme.c @@ -1293,6 +1293,19 @@ int vme_slot_get(struct vme_dev *vdev) } EXPORT_SYMBOL(vme_slot_get); +int vme_bus_num(struct vme_dev *vdev) +{ + struct vme_bridge *bridge; + + bridge = vdev->bridge; + if (bridge == NULL) { + pr_err("Can't find VME bus\n"); + return -EINVAL; + } + + return bridge->num; +} +EXPORT_SYMBOL(vme_bus_num); /* - Bridge Registration --------------------------------------------------- */ diff --git a/include/linux/vme.h b/include/linux/vme.h index c9d65bf14cec..4eb42c8f097d 100644 --- a/include/linux/vme.h +++ b/include/linux/vme.h @@ -165,6 +165,7 @@ int vme_lm_detach(struct vme_resource *, int); void vme_lm_free(struct vme_resource *); int vme_slot_get(struct vme_dev *); +int vme_bus_num(struct vme_dev *); int vme_register_driver(struct vme_driver *, unsigned int); void vme_unregister_driver(struct vme_driver *); -- cgit v1.2.3-59-g8ed1b From d7729f0fc40296f91b483dfb929e71b27cf75345 Mon Sep 17 00:00:00 2001 From: Martyn Welch Date: Fri, 8 Nov 2013 11:58:35 +0000 Subject: VME: Rename vme_slot_get to avoid confusion with reference counting Traditionally the "get" functions increment the reference count of the object that is returned, which does not happen with vme_slot_get. The function vme_slot_get returns the physical VME slot associated with a particular struct vme_dev. Rename vme_slot_num to avoid any confusion. Signed-off-by: Martyn Welch Signed-off-by: Greg Kroah-Hartman --- Documentation/vme_api.txt | 2 +- drivers/staging/vme/devices/vme_user.c | 2 +- drivers/vme/vme.c | 6 +++--- include/linux/vme.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/Documentation/vme_api.txt b/Documentation/vme_api.txt index 126a1f1d5151..ffe6e22a2ccd 100644 --- a/Documentation/vme_api.txt +++ b/Documentation/vme_api.txt @@ -393,7 +393,7 @@ Slot Detection This function returns the slot ID of the provided bridge. - int vme_slot_get(struct vme_dev *dev); + int vme_slot_num(struct vme_dev *dev); Bus Detection diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index caee906f9b38..bc4f8623c8cc 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -666,7 +666,7 @@ static int vme_user_match(struct vme_dev *vdev) int i; int cur_bus = vme_bus_num(vdev); - int cur_slot = vme_slot_get(vdev); + int cur_slot = vme_slot_num(vdev); for (i = 0; i < bus_num; i++) if ((cur_bus == bus[i]) && (cur_slot == vdev->num)) diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c index 8df5e4efc1ca..96562c9a8b1b 100644 --- a/drivers/vme/vme.c +++ b/drivers/vme/vme.c @@ -1274,7 +1274,7 @@ void vme_lm_free(struct vme_resource *resource) } EXPORT_SYMBOL(vme_lm_free); -int vme_slot_get(struct vme_dev *vdev) +int vme_slot_num(struct vme_dev *vdev) { struct vme_bridge *bridge; @@ -1285,13 +1285,13 @@ int vme_slot_get(struct vme_dev *vdev) } if (bridge->slot_get == NULL) { - printk(KERN_WARNING "vme_slot_get not supported\n"); + printk(KERN_WARNING "vme_slot_num not supported\n"); return -EINVAL; } return bridge->slot_get(bridge); } -EXPORT_SYMBOL(vme_slot_get); +EXPORT_SYMBOL(vme_slot_num); int vme_bus_num(struct vme_dev *vdev) { diff --git a/include/linux/vme.h b/include/linux/vme.h index 4eb42c8f097d..8cd6f19ca518 100644 --- a/include/linux/vme.h +++ b/include/linux/vme.h @@ -164,7 +164,7 @@ int vme_lm_attach(struct vme_resource *, int, void (*callback)(int)); int vme_lm_detach(struct vme_resource *, int); void vme_lm_free(struct vme_resource *); -int vme_slot_get(struct vme_dev *); +int vme_slot_num(struct vme_dev *); int vme_bus_num(struct vme_dev *); int vme_register_driver(struct vme_driver *, unsigned int); -- cgit v1.2.3-59-g8ed1b From 647cc7b9be861e01723a3183f5d06729a1613a97 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 25 Nov 2013 14:56:00 +0000 Subject: iio: Add data_available callback for buffers This patch adds a new data_available() callback to the iio_buffer_access_funcs struct. The callback is used to indicate whether data is available in the buffer for reading. It is meant to replace the stufftoread flag from the iio_buffer struct. The reasoning for this is that the buffer implementation usually can determine whether data is available rather easily based on its state, on the other hand it can be rather tricky to update the stufftoread flag in a race free way. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/industrialio-buffer.c | 10 +++++++++- include/linux/iio/buffer.h | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 7f9152c3c4d3..4dcc3a0f9930 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -37,6 +37,14 @@ static bool iio_buffer_is_active(struct iio_buffer *buf) return !list_empty(&buf->buffer_list); } +static bool iio_buffer_data_available(struct iio_buffer *buf) +{ + if (buf->access->data_available) + return buf->access->data_available(buf); + + return buf->stufftoread; +} + /** * iio_buffer_read_first_n_outer() - chrdev read for buffer access * @@ -70,7 +78,7 @@ unsigned int iio_buffer_poll(struct file *filp, return -ENODEV; poll_wait(filp, &rb->pollq, wait); - if (rb->stufftoread) + if (iio_buffer_data_available(rb)) return POLLIN | POLLRDNORM; /* need a way of knowing if there may be enough data... */ return 0; diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index 15607b45221a..519392763393 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -21,6 +21,8 @@ struct iio_buffer; * struct iio_buffer_access_funcs - access functions for buffers. * @store_to: actually store stuff to the buffer * @read_first_n: try to get a specified number of bytes (must exist) + * @data_available: indicates whether data for reading from the buffer is + * available. * @request_update: if a parameter change has been marked, update underlying * storage. * @get_bytes_per_datum:get current bytes per datum @@ -43,6 +45,7 @@ struct iio_buffer_access_funcs { int (*read_first_n)(struct iio_buffer *buffer, size_t n, char __user *buf); + bool (*data_available)(struct iio_buffer *buffer); int (*request_update)(struct iio_buffer *buffer); -- cgit v1.2.3-59-g8ed1b From ac216aa290c48a5e9d7b9f2473abb977a175683a Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Sun, 1 Dec 2013 15:08:00 +0000 Subject: iio: Add support for humidity sensors There are already humidity sensors in the hwmon subsystem, so we use their unit (milli percent) here as well. Signed-off-by: Harald Geyer Signed-off-by: Jonathan Cameron --- Documentation/ABI/testing/sysfs-bus-iio | 13 +++++++++++++ drivers/iio/industrialio-core.c | 1 + include/linux/iio/types.h | 1 + 3 files changed, 15 insertions(+) (limited to 'include/linux') diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio index b20e829d350f..6e02c5029152 100644 --- a/Documentation/ABI/testing/sysfs-bus-iio +++ b/Documentation/ABI/testing/sysfs-bus-iio @@ -197,6 +197,19 @@ Description: Raw pressure measurement from channel Y. Units after application of scale and offset are kilopascal. +What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_raw +KernelVersion: 3.14 +Contact: linux-iio@vger.kernel.org +Description: + Raw humidity measurement of air. Units after application of + scale and offset are milli percent. + +What: /sys/bus/iio/devices/iio:deviceX/in_humidityrelative_input +KernelVersion: 3.14 +Contact: linux-iio@vger.kernel.org +Description: + Scaled humidity measurement in milli percent. + What: /sys/bus/iio/devices/iio:deviceX/in_accel_offset What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_offset What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_offset diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 2fe88c189f74..acc911a836ca 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -69,6 +69,7 @@ static const char * const iio_chan_type_name_spec[] = { [IIO_ALTVOLTAGE] = "altvoltage", [IIO_CCT] = "cct", [IIO_PRESSURE] = "pressure", + [IIO_HUMIDITYRELATIVE] = "humidityrelative", }; static const char * const iio_modifier_names[] = { diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 4ac928ee31c5..084d882fe01b 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -29,6 +29,7 @@ enum iio_chan_type { IIO_ALTVOLTAGE, IIO_CCT, IIO_PRESSURE, + IIO_HUMIDITYRELATIVE, }; enum iio_modifier { -- cgit v1.2.3-59-g8ed1b From 098d3beccfb6d678a926c4cc4f5e70c3b752fd5e Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Wed, 6 Nov 2013 00:11:00 +0000 Subject: iio: hid-sensors: Added Inclinometer 3D Added usage id processing for Inclinometer 3D. This uses IIO interfaces for triggered buffer to present data to user mode.This uses HID sensor framework for registering callback events from the sensor hub. Signed-off-by: Srinivas Pandruvada Signed-off-by: Jonathan Cameron --- drivers/iio/Kconfig | 1 + drivers/iio/Makefile | 1 + drivers/iio/orientation/Kconfig | 19 ++ drivers/iio/orientation/Makefile | 6 + drivers/iio/orientation/hid-sensor-incl-3d.c | 428 +++++++++++++++++++++++++++ include/linux/hid-sensor-ids.h | 4 + 6 files changed, 459 insertions(+) create mode 100644 drivers/iio/orientation/Kconfig create mode 100644 drivers/iio/orientation/Makefile create mode 100644 drivers/iio/orientation/hid-sensor-incl-3d.c (limited to 'include/linux') diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index a5ed88226276..5dd0e120a504 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -69,6 +69,7 @@ source "drivers/iio/humidity/Kconfig" source "drivers/iio/imu/Kconfig" source "drivers/iio/light/Kconfig" source "drivers/iio/magnetometer/Kconfig" +source "drivers/iio/orientation/Kconfig" if IIO_TRIGGER source "drivers/iio/trigger/Kconfig" endif #IIO_TRIGGER diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index b3b50968b46b..887d39090d75 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -22,6 +22,7 @@ obj-y += humidity/ obj-y += imu/ obj-y += light/ obj-y += magnetometer/ +obj-y += orientation/ obj-y += pressure/ obj-y += temperature/ obj-y += trigger/ diff --git a/drivers/iio/orientation/Kconfig b/drivers/iio/orientation/Kconfig new file mode 100644 index 000000000000..58c62c837e12 --- /dev/null +++ b/drivers/iio/orientation/Kconfig @@ -0,0 +1,19 @@ +# +# Inclinometer sensors +# +# When adding new entries keep the list in alphabetical order + +menu "Inclinometer sensors" + +config HID_SENSOR_INCLINOMETER_3D + depends on HID_SENSOR_HUB + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select HID_SENSOR_IIO_COMMON + select HID_SENSOR_IIO_TRIGGER + tristate "HID Inclinometer 3D" + help + Say yes here to build support for the HID SENSOR + Inclinometer 3D. + +endmenu diff --git a/drivers/iio/orientation/Makefile b/drivers/iio/orientation/Makefile new file mode 100644 index 000000000000..2c97572ee919 --- /dev/null +++ b/drivers/iio/orientation/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for industrial I/O Inclinometer sensor drivers +# + +# When adding new entries keep the list in alphabetical order +obj-$(CONFIG_HID_SENSOR_INCLINOMETER_3D) += hid-sensor-incl-3d.o diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c new file mode 100644 index 000000000000..070feab08faa --- /dev/null +++ b/drivers/iio/orientation/hid-sensor-incl-3d.c @@ -0,0 +1,428 @@ +/* + * HID Sensors Driver + * Copyright (c) 2013, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../common/hid-sensors/hid-sensor-trigger.h" + +enum incl_3d_channel { + CHANNEL_SCAN_INDEX_X, + CHANNEL_SCAN_INDEX_Y, + CHANNEL_SCAN_INDEX_Z, + INCLI_3D_CHANNEL_MAX, +}; + +struct incl_3d_state { + struct hid_sensor_hub_callbacks callbacks; + struct hid_sensor_common common_attributes; + struct hid_sensor_hub_attribute_info incl[INCLI_3D_CHANNEL_MAX]; + u32 incl_val[INCLI_3D_CHANNEL_MAX]; +}; + +static const u32 incl_3d_addresses[INCLI_3D_CHANNEL_MAX] = { + HID_USAGE_SENSOR_ORIENT_TILT_X, + HID_USAGE_SENSOR_ORIENT_TILT_Y, + HID_USAGE_SENSOR_ORIENT_TILT_Z +}; + +/* Channel definitions */ +static const struct iio_chan_spec incl_3d_channels[] = { + { + .type = IIO_INCLI, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + .scan_index = CHANNEL_SCAN_INDEX_X, + }, { + .type = IIO_INCLI, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + .scan_index = CHANNEL_SCAN_INDEX_Y, + }, { + .type = IIO_INCLI, + .modified = 1, + .channel2 = IIO_MOD_Z, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_OFFSET) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_HYSTERESIS), + .scan_index = CHANNEL_SCAN_INDEX_Z, + } +}; + +/* Adjust channel real bits based on report descriptor */ +static void incl_3d_adjust_channel_bit_mask(struct iio_chan_spec *chan, + int size) +{ + chan->scan_type.sign = 's'; + /* Real storage bits will change based on the report desc. */ + chan->scan_type.realbits = size * 8; + /* Maximum size of a sample to capture is u32 */ + chan->scan_type.storagebits = sizeof(u32) * 8; +} + +/* Channel read_raw handler */ +static int incl_3d_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct incl_3d_state *incl_state = iio_priv(indio_dev); + int report_id = -1; + u32 address; + int ret_type; + + *val = 0; + *val2 = 0; + switch (mask) { + case IIO_CHAN_INFO_RAW: + report_id = + incl_state->incl[chan->scan_index].report_id; + address = incl_3d_addresses[chan->scan_index]; + if (report_id >= 0) + *val = sensor_hub_input_attr_get_raw_value( + incl_state->common_attributes.hsdev, + HID_USAGE_SENSOR_INCLINOMETER_3D, address, + report_id); + else { + return -EINVAL; + } + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SCALE: + *val = incl_state->incl[CHANNEL_SCAN_INDEX_X].units; + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_OFFSET: + *val = hid_sensor_convert_exponent( + incl_state->incl[CHANNEL_SCAN_INDEX_X].unit_expo); + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret_type = hid_sensor_read_samp_freq_value( + &incl_state->common_attributes, val, val2); + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret_type = hid_sensor_read_raw_hyst_value( + &incl_state->common_attributes, val, val2); + break; + default: + ret_type = -EINVAL; + break; + } + + return ret_type; +} + +/* Channel write_raw handler */ +static int incl_3d_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct incl_3d_state *incl_state = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_write_samp_freq_value( + &incl_state->common_attributes, val, val2); + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_write_raw_hyst_value( + &incl_state->common_attributes, val, val2); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct iio_info incl_3d_info = { + .driver_module = THIS_MODULE, + .read_raw = &incl_3d_read_raw, + .write_raw = &incl_3d_write_raw, +}; + +/* Function to push data to buffer */ +static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +{ + dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); + iio_push_to_buffers(indio_dev, (u8 *)data); +} + +/* Callback handler to send event after all samples are received and captured */ +static int incl_3d_proc_event(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + void *priv) +{ + struct iio_dev *indio_dev = platform_get_drvdata(priv); + struct incl_3d_state *incl_state = iio_priv(indio_dev); + + dev_dbg(&indio_dev->dev, "incl_3d_proc_event [%d]\n", + incl_state->common_attributes.data_ready); + if (incl_state->common_attributes.data_ready) + hid_sensor_push_data(indio_dev, + (u8 *)incl_state->incl_val, + sizeof(incl_state->incl_val)); + + return 0; +} + +/* Capture samples in local storage */ +static int incl_3d_capture_sample(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + size_t raw_len, char *raw_data, + void *priv) +{ + struct iio_dev *indio_dev = platform_get_drvdata(priv); + struct incl_3d_state *incl_state = iio_priv(indio_dev); + int ret = 0; + + switch (usage_id) { + case HID_USAGE_SENSOR_ORIENT_TILT_X: + incl_state->incl_val[CHANNEL_SCAN_INDEX_X] = *(u32 *)raw_data; + break; + case HID_USAGE_SENSOR_ORIENT_TILT_Y: + incl_state->incl_val[CHANNEL_SCAN_INDEX_Y] = *(u32 *)raw_data; + break; + case HID_USAGE_SENSOR_ORIENT_TILT_Z: + incl_state->incl_val[CHANNEL_SCAN_INDEX_Z] = *(u32 *)raw_data; + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} + +/* Parse report which is specific to an usage id*/ +static int incl_3d_parse_report(struct platform_device *pdev, + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + unsigned usage_id, + struct incl_3d_state *st) +{ + int ret; + + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_ORIENT_TILT_X, + &st->incl[CHANNEL_SCAN_INDEX_X]); + if (ret) + return ret; + incl_3d_adjust_channel_bit_mask(&channels[CHANNEL_SCAN_INDEX_X], + st->incl[CHANNEL_SCAN_INDEX_X].size); + + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_ORIENT_TILT_Y, + &st->incl[CHANNEL_SCAN_INDEX_Y]); + if (ret) + return ret; + incl_3d_adjust_channel_bit_mask(&channels[CHANNEL_SCAN_INDEX_Y], + st->incl[CHANNEL_SCAN_INDEX_Y].size); + + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_ORIENT_TILT_Z, + &st->incl[CHANNEL_SCAN_INDEX_Z]); + if (ret) + return ret; + incl_3d_adjust_channel_bit_mask(&channels[CHANNEL_SCAN_INDEX_Z], + st->incl[CHANNEL_SCAN_INDEX_Z].size); + + dev_dbg(&pdev->dev, "incl_3d %x:%x, %x:%x, %x:%x\n", + st->incl[0].index, + st->incl[0].report_id, + st->incl[1].index, st->incl[1].report_id, + st->incl[2].index, st->incl[2].report_id); + + /* Set Sensitivity field ids, when there is no individual modifier */ + if (st->common_attributes.sensitivity.index < 0) { + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | + HID_USAGE_SENSOR_DATA_ORIENTATION, + &st->common_attributes.sensitivity); + dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", + st->common_attributes.sensitivity.index, + st->common_attributes.sensitivity.report_id); + } + return ret; +} + +/* Function to initialize the processing for usage id */ +static int hid_incl_3d_probe(struct platform_device *pdev) +{ + int ret; + static char *name = "incli_3d"; + struct iio_dev *indio_dev; + struct incl_3d_state *incl_state; + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_chan_spec *channels; + + indio_dev = devm_iio_device_alloc(&pdev->dev, + sizeof(struct incl_3d_state)); + if (indio_dev == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, indio_dev); + + incl_state = iio_priv(indio_dev); + incl_state->common_attributes.hsdev = hsdev; + incl_state->common_attributes.pdev = pdev; + + ret = hid_sensor_parse_common_attributes(hsdev, + HID_USAGE_SENSOR_INCLINOMETER_3D, + &incl_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "failed to setup common attributes\n"); + return ret; + } + + channels = kmemdup(incl_3d_channels, sizeof(incl_3d_channels), + GFP_KERNEL); + if (!channels) { + dev_err(&pdev->dev, "failed to duplicate channels\n"); + return -ENOMEM; + } + + ret = incl_3d_parse_report(pdev, hsdev, channels, + HID_USAGE_SENSOR_INCLINOMETER_3D, incl_state); + if (ret) { + dev_err(&pdev->dev, "failed to setup attributes\n"); + goto error_free_dev_mem; + } + + indio_dev->channels = channels; + indio_dev->num_channels = ARRAY_SIZE(incl_3d_channels); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &incl_3d_info; + indio_dev->name = name; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + NULL, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); + goto error_free_dev_mem; + } + incl_state->common_attributes.data_ready = false; + ret = hid_sensor_setup_trigger(indio_dev, name, + &incl_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "trigger setup failed\n"); + goto error_unreg_buffer_funcs; + } + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&pdev->dev, "device register failed\n"); + goto error_remove_trigger; + } + + incl_state->callbacks.send_event = incl_3d_proc_event; + incl_state->callbacks.capture_sample = incl_3d_capture_sample; + incl_state->callbacks.pdev = pdev; + ret = sensor_hub_register_callback(hsdev, + HID_USAGE_SENSOR_INCLINOMETER_3D, + &incl_state->callbacks); + if (ret) { + dev_err(&pdev->dev, "callback reg failed\n"); + goto error_iio_unreg; + } + + return 0; + +error_iio_unreg: + iio_device_unregister(indio_dev); +error_remove_trigger: + hid_sensor_remove_trigger(&incl_state->common_attributes); +error_unreg_buffer_funcs: + iio_triggered_buffer_cleanup(indio_dev); +error_free_dev_mem: + kfree(indio_dev->channels); + return ret; +} + +/* Function to deinitialize the processing for usage id */ +static int hid_incl_3d_remove(struct platform_device *pdev) +{ + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct incl_3d_state *incl_state = iio_priv(indio_dev); + + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_INCLINOMETER_3D); + iio_device_unregister(indio_dev); + hid_sensor_remove_trigger(&incl_state->common_attributes); + iio_triggered_buffer_cleanup(indio_dev); + kfree(indio_dev->channels); + + return 0; +} + +static struct platform_device_id hid_incl_3d_ids[] = { + { + /* Format: HID-SENSOR-usage_id_in_hex_lowercase */ + .name = "HID-SENSOR-200086", + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, hid_incl_3d_ids); + +static struct platform_driver hid_incl_3d_platform_driver = { + .id_table = hid_incl_3d_ids, + .driver = { + .name = KBUILD_MODNAME, + .owner = THIS_MODULE, + }, + .probe = hid_incl_3d_probe, + .remove = hid_incl_3d_remove, +}; +module_platform_driver(hid_incl_3d_platform_driver); + +MODULE_DESCRIPTION("HID Sensor Inclinometer 3D"); +MODULE_AUTHOR("Srinivas Pandruvada "); +MODULE_LICENSE("GPL"); diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h index 4cc165887b09..558b7d43de7d 100644 --- a/include/linux/hid-sensor-ids.h +++ b/include/linux/hid-sensor-ids.h @@ -58,10 +58,14 @@ #define HID_USAGE_SENSOR_ORIENT_DISTANCE_Y 0x20047B #define HID_USAGE_SENSOR_ORIENT_DISTANCE_Z 0x20047C #define HID_USAGE_SENSOR_ORIENT_DISTANCE_OUT_OF_RANGE 0x20047D + +/* ORIENTATION: Inclinometer 3D: (200086) */ +#define HID_USAGE_SENSOR_INCLINOMETER_3D 0x200086 #define HID_USAGE_SENSOR_ORIENT_TILT 0x20047E #define HID_USAGE_SENSOR_ORIENT_TILT_X 0x20047F #define HID_USAGE_SENSOR_ORIENT_TILT_Y 0x200480 #define HID_USAGE_SENSOR_ORIENT_TILT_Z 0x200481 + #define HID_USAGE_SENSOR_ORIENT_ROTATION_MATRIX 0x200482 #define HID_USAGE_SENSOR_ORIENT_QUATERNION 0x200483 #define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX 0x200484 -- cgit v1.2.3-59-g8ed1b From 74e22fac8858f83af9b589f1dcb004ccf4991003 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 4 Dec 2013 14:09:38 +1030 Subject: module.h: Remove unnecessary semicolon [All 8 callers already have semicolons. -- RR] Signed-off-by: Joe Perches Signed-off-by: Rusty Russell --- include/linux/module.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/module.h b/include/linux/module.h index 15cd6b1b211e..46e548fd502a 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -451,7 +451,7 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, extern void __module_put_and_exit(struct module *mod, long code) __attribute__((noreturn)); -#define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code); +#define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code) #ifdef CONFIG_MODULE_UNLOAD unsigned long module_refcount(struct module *mod); -- cgit v1.2.3-59-g8ed1b From 4e5e4705bf69ea450f58fc709ac5888f321a9299 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Wed, 3 Jul 2013 15:35:39 -0400 Subject: thermal: introduce device tree parser This patch introduces a device tree bindings for describing the hardware thermal behavior and limits. Also a parser to read and interpret the data and feed it in the thermal framework is presented. This patch introduces a thermal data parser for device tree. The parsed data is used to build thermal zones and thermal binding parameters. The output data can then be used to deploy thermal policies. This patch adds also documentation regarding this API and how to define tree nodes to use this infrastructure. Note that, in order to be able to have control on the sensor registration on the DT thermal zone, it was required to allow changing the thermal zone .get_temp callback. For this reason, this patch also removes the 'const' modifier from the .ops field of thermal zone devices. Cc: Zhang Rui Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Acked-by: Mark Rutland Signed-off-by: Eduardo Valentin --- .../devicetree/bindings/thermal/thermal.txt | 595 +++++++++++++++ drivers/thermal/Kconfig | 13 + drivers/thermal/Makefile | 1 + drivers/thermal/of-thermal.c | 849 +++++++++++++++++++++ drivers/thermal/thermal_core.c | 9 +- drivers/thermal/thermal_core.h | 9 + include/dt-bindings/thermal/thermal.h | 17 + include/linux/thermal.h | 28 +- 8 files changed, 1518 insertions(+), 3 deletions(-) create mode 100644 Documentation/devicetree/bindings/thermal/thermal.txt create mode 100644 drivers/thermal/of-thermal.c create mode 100644 include/dt-bindings/thermal/thermal.h (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/thermal/thermal.txt b/Documentation/devicetree/bindings/thermal/thermal.txt new file mode 100644 index 000000000000..f5db6b72a36f --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/thermal.txt @@ -0,0 +1,595 @@ +* Thermal Framework Device Tree descriptor + +This file describes a generic binding to provide a way of +defining hardware thermal structure using device tree. +A thermal structure includes thermal zones and their components, +such as trip points, polling intervals, sensors and cooling devices +binding descriptors. + +The target of device tree thermal descriptors is to describe only +the hardware thermal aspects. The thermal device tree bindings are +not about how the system must control or which algorithm or policy +must be taken in place. + +There are five types of nodes involved to describe thermal bindings: +- thermal sensors: devices which may be used to take temperature + measurements. +- cooling devices: devices which may be used to dissipate heat. +- trip points: describe key temperatures at which cooling is recommended. The + set of points should be chosen based on hardware limits. +- cooling maps: used to describe links between trip points and cooling devices; +- thermal zones: used to describe thermal data within the hardware; + +The following is a description of each of these node types. + +* Thermal sensor devices + +Thermal sensor devices are nodes providing temperature sensing capabilities on +thermal zones. Typical devices are I2C ADC converters and bandgaps. These are +nodes providing temperature data to thermal zones. Thermal sensor devices may +control one or more internal sensors. + +Required property: +- #thermal-sensor-cells: Used to provide sensor device specific information + Type: unsigned while referring to it. Typically 0 on thermal sensor + Size: one cell nodes with only one sensor, and at least 1 on nodes + with several internal sensors, in order + to identify uniquely the sensor instances within + the IC. See thermal zone binding for more details + on how consumers refer to sensor devices. + +* Cooling device nodes + +Cooling devices are nodes providing control on power dissipation. There +are essentially two ways to provide control on power dissipation. First +is by means of regulating device performance, which is known as passive +cooling. A typical passive cooling is a CPU that has dynamic voltage and +frequency scaling (DVFS), and uses lower frequencies as cooling states. +Second is by means of activating devices in order to remove +the dissipated heat, which is known as active cooling, e.g. regulating +fan speeds. In both cases, cooling devices shall have a way to determine +the state of cooling in which the device is. + +Any cooling device has a range of cooling states (i.e. different levels +of heat dissipation). For example a fan's cooling states correspond to +the different fan speeds possible. Cooling states are referred to by +single unsigned integers, where larger numbers mean greater heat +dissipation. The precise set of cooling states associated with a device +(as referred to be the cooling-min-state and cooling-max-state +properties) should be defined in a particular device's binding. +For more examples of cooling devices, refer to the example sections below. + +Required properties: +- cooling-min-state: An integer indicating the smallest + Type: unsigned cooling state accepted. Typically 0. + Size: one cell + +- cooling-max-state: An integer indicating the largest + Type: unsigned cooling state accepted. + Size: one cell + +- #cooling-cells: Used to provide cooling device specific information + Type: unsigned while referring to it. Must be at least 2, in order + Size: one cell to specify minimum and maximum cooling state used + in the reference. The first cell is the minimum + cooling state requested and the second cell is + the maximum cooling state requested in the reference. + See Cooling device maps section below for more details + on how consumers refer to cooling devices. + +* Trip points + +The trip node is a node to describe a point in the temperature domain +in which the system takes an action. This node describes just the point, +not the action. + +Required properties: +- temperature: An integer indicating the trip temperature level, + Type: signed in millicelsius. + Size: one cell + +- hysteresis: A low hysteresis value on temperature property (above). + Type: unsigned This is a relative value, in millicelsius. + Size: one cell + +- type: a string containing the trip type. Expected values are: + "active": A trip point to enable active cooling + "passive": A trip point to enable passive cooling + "hot": A trip point to notify emergency + "critical": Hardware not reliable. + Type: string + +* Cooling device maps + +The cooling device maps node is a node to describe how cooling devices +get assigned to trip points of the zone. The cooling devices are expected +to be loaded in the target system. + +Required properties: +- cooling-device: A phandle of a cooling device with its specifier, + Type: phandle + referring to which cooling device is used in this + cooling specifier binding. In the cooling specifier, the first cell + is the minimum cooling state and the second cell + is the maximum cooling state used in this map. +- trip: A phandle of a trip point node within the same thermal + Type: phandle of zone. + trip point node + +Optional property: +- contribution: The cooling contribution to the thermal zone of the + Type: unsigned referred cooling device at the referred trip point. + Size: one cell The contribution is a ratio of the sum + of all cooling contributions within a thermal zone. + +Note: Using the THERMAL_NO_LIMIT (-1UL) constant in the cooling-device phandle +limit specifier means: +(i) - minimum state allowed for minimum cooling state used in the reference. +(ii) - maximum state allowed for maximum cooling state used in the reference. +Refer to include/dt-bindings/thermal/thermal.h for definition of this constant. + +* Thermal zone nodes + +The thermal zone node is the node containing all the required info +for describing a thermal zone, including its cooling device bindings. The +thermal zone node must contain, apart from its own properties, one sub-node +containing trip nodes and one sub-node containing all the zone cooling maps. + +Required properties: +- polling-delay: The maximum number of milliseconds to wait between polls + Type: unsigned when checking this thermal zone. + Size: one cell + +- polling-delay-passive: The maximum number of milliseconds to wait + Type: unsigned between polls when performing passive cooling. + Size: one cell + +- thermal-sensors: A list of thermal sensor phandles and sensor specifier + Type: list of used while monitoring the thermal zone. + phandles + sensor + specifier + +- trips: A sub-node which is a container of only trip point nodes + Type: sub-node required to describe the thermal zone. + +- cooling-maps: A sub-node which is a container of only cooling device + Type: sub-node map nodes, used to describe the relation between trips + and cooling devices. + +Optional property: +- coefficients: An array of integers (one signed cell) containing + Type: array coefficients to compose a linear relation between + Elem size: one cell the sensors listed in the thermal-sensors property. + Elem type: signed Coefficients defaults to 1, in case this property + is not specified. A simple linear polynomial is used: + Z = c0 * x0 + c1 + x1 + ... + c(n-1) * x(n-1) + cn. + + The coefficients are ordered and they match with sensors + by means of sensor ID. Additional coefficients are + interpreted as constant offset. + +Note: The delay properties are bound to the maximum dT/dt (temperature +derivative over time) in two situations for a thermal zone: +(i) - when passive cooling is activated (polling-delay-passive); and +(ii) - when the zone just needs to be monitored (polling-delay) or +when active cooling is activated. + +The maximum dT/dt is highly bound to hardware power consumption and dissipation +capability. The delays should be chosen to account for said max dT/dt, +such that a device does not cross several trip boundaries unexpectedly +between polls. Choosing the right polling delays shall avoid having the +device in temperature ranges that may damage the silicon structures and +reduce silicon lifetime. + +* The thermal-zones node + +The "thermal-zones" node is a container for all thermal zone nodes. It shall +contain only sub-nodes describing thermal zones as in the section +"Thermal zone nodes". The "thermal-zones" node appears under "/". + +* Examples + +Below are several examples on how to use thermal data descriptors +using device tree bindings: + +(a) - CPU thermal zone + +The CPU thermal zone example below describes how to setup one thermal zone +using one single sensor as temperature source and many cooling devices and +power dissipation control sources. + +#include + +cpus { + /* + * Here is an example of describing a cooling device for a DVFS + * capable CPU. The CPU node describes its four OPPs. + * The cooling states possible are 0..3, and they are + * used as OPP indexes. The minimum cooling state is 0, which means + * all four OPPs can be available to the system. The maximum + * cooling state is 3, which means only the lowest OPPs (198MHz@0.85V) + * can be available in the system. + */ + cpu0: cpu@0 { + ... + operating-points = < + /* kHz uV */ + 970000 1200000 + 792000 1100000 + 396000 950000 + 198000 850000 + >; + cooling-min-state = <0>; + cooling-max-state = <3>; + #cooling-cells = <2>; /* min followed by max */ + }; + ... +}; + +&i2c1 { + ... + /* + * A simple fan controller which supports 10 speeds of operation + * (represented as 0-9). + */ + fan0: fan@0x48 { + ... + cooling-min-state = <0>; + cooling-max-state = <9>; + #cooling-cells = <2>; /* min followed by max */ + }; +}; + +ocp { + ... + /* + * A simple IC with a single bandgap temperature sensor. + */ + bandgap0: bandgap@0x0000ED00 { + ... + #thermal-sensor-cells = <0>; + }; +}; + +thermal-zones { + cpu-thermal: cpu-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + thermal-sensors = <&bandgap0>; + + trips { + cpu-alert0: cpu-alert { + temperature = <90000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "active"; + }; + cpu-alert1: cpu-alert { + temperature = <100000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + cpu-crit: cpu-crit { + temperature = <125000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu-alert0>; + cooling-device = <&fan0 THERMAL_NO_LIMITS 4>; + }; + map1 { + trip = <&cpu-alert1>; + cooling-device = <&fan0 5 THERMAL_NO_LIMITS>; + }; + map2 { + trip = <&cpu-alert1>; + cooling-device = + <&cpu0 THERMAL_NO_LIMITS THERMAL_NO_LIMITS>; + }; + }; + }; +}; + +In the example above, the ADC sensor (bandgap0) at address 0x0000ED00 is +used to monitor the zone 'cpu-thermal' using its sole sensor. A fan +device (fan0) is controlled via I2C bus 1, at address 0x48, and has ten +different cooling states 0-9. It is used to remove the heat out of +the thermal zone 'cpu-thermal' using its cooling states +from its minimum to 4, when it reaches trip point 'cpu-alert0' +at 90C, as an example of active cooling. The same cooling device is used at +'cpu-alert1', but from 5 to its maximum state. The cpu@0 device is also +linked to the same thermal zone, 'cpu-thermal', as a passive cooling device, +using all its cooling states at trip point 'cpu-alert1', +which is a trip point at 100C. On the thermal zone 'cpu-thermal', at the +temperature of 125C, represented by the trip point 'cpu-crit', the silicon +is not reliable anymore. + +(b) - IC with several internal sensors + +The example below describes how to deploy several thermal zones based off a +single sensor IC, assuming it has several internal sensors. This is a common +case on SoC designs with several internal IPs that may need different thermal +requirements, and thus may have their own sensor to monitor or detect internal +hotspots in their silicon. + +#include + +ocp { + ... + /* + * A simple IC with several bandgap temperature sensors. + */ + bandgap0: bandgap@0x0000ED00 { + ... + #thermal-sensor-cells = <1>; + }; +}; + +thermal-zones { + cpu-thermal: cpu-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&bandgap0 0>; + + trips { + /* each zone within the SoC may have its own trips */ + cpu-alert: cpu-alert { + temperature = <100000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + cpu-crit: cpu-crit { + temperature = <125000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + /* each zone within the SoC may have its own cooling */ + ... + }; + }; + + gpu-thermal: gpu-thermal { + polling-delay-passive = <120>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&bandgap0 1>; + + trips { + /* each zone within the SoC may have its own trips */ + gpu-alert: gpu-alert { + temperature = <90000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + gpu-crit: gpu-crit { + temperature = <105000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + /* each zone within the SoC may have its own cooling */ + ... + }; + }; + + dsp-thermal: dsp-thermal { + polling-delay-passive = <50>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&bandgap0 2>; + + trips { + /* each zone within the SoC may have its own trips */ + dsp-alert: gpu-alert { + temperature = <90000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + dsp-crit: gpu-crit { + temperature = <135000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + /* each zone within the SoC may have its own cooling */ + ... + }; + }; +}; + +In the example above, there is one bandgap IC which has the capability to +monitor three sensors. The hardware has been designed so that sensors are +placed on different places in the DIE to monitor different temperature +hotspots: one for CPU thermal zone, one for GPU thermal zone and the +other to monitor a DSP thermal zone. + +Thus, there is a need to assign each sensor provided by the bandgap IC +to different thermal zones. This is achieved by means of using the +#thermal-sensor-cells property and using the first cell of the sensor +specifier as sensor ID. In the example, then, is used to +monitor CPU thermal zone, is used to monitor GPU thermal +zone and is used to monitor DSP thermal zone. Each zone +may be uncorrelated, having its own dT/dt requirements, trips +and cooling maps. + + +(c) - Several sensors within one single thermal zone + +The example below illustrates how to use more than one sensor within +one thermal zone. + +#include + +&i2c1 { + ... + /* + * A simple IC with a single temperature sensor. + */ + adc: sensor@0x49 { + ... + #thermal-sensor-cells = <0>; + }; +}; + +ocp { + ... + /* + * A simple IC with a single bandgap temperature sensor. + */ + bandgap0: bandgap@0x0000ED00 { + ... + #thermal-sensor-cells = <0>; + }; +}; + +thermal-zones { + cpu-thermal: cpu-thermal { + polling-delay-passive = <250>; /* milliseconds */ + polling-delay = <1000>; /* milliseconds */ + + thermal-sensors = <&bandgap0>, /* cpu */ + <&adc>; /* pcb north */ + + /* hotspot = 100 * bandgap - 120 * adc + 484 */ + coefficients = <100 -120 484>; + + trips { + ... + }; + + cooling-maps { + ... + }; + }; +}; + +In some cases, there is a need to use more than one sensor to extrapolate +a thermal hotspot in the silicon. The above example illustrates this situation. +For instance, it may be the case that a sensor external to CPU IP may be placed +close to CPU hotspot and together with internal CPU sensor, it is used +to determine the hotspot. Assuming this is the case for the above example, +the hypothetical extrapolation rule would be: + hotspot = 100 * bandgap - 120 * adc + 484 + +In other context, the same idea can be used to add fixed offset. For instance, +consider the hotspot extrapolation rule below: + hotspot = 1 * adc + 6000 + +In the above equation, the hotspot is always 6C higher than what is read +from the ADC sensor. The binding would be then: + thermal-sensors = <&adc>; + + /* hotspot = 1 * adc + 6000 */ + coefficients = <1 6000>; + +(d) - Board thermal + +The board thermal example below illustrates how to setup one thermal zone +with many sensors and many cooling devices. + +#include + +&i2c1 { + ... + /* + * An IC with several temperature sensor. + */ + adc-dummy: sensor@0x50 { + ... + #thermal-sensor-cells = <1>; /* sensor internal ID */ + }; +}; + +thermal-zones { + batt-thermal { + polling-delay-passive = <500>; /* milliseconds */ + polling-delay = <2500>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&adc-dummy 4>; + + trips { + ... + }; + + cooling-maps { + ... + }; + }; + + board-thermal: board-thermal { + polling-delay-passive = <1000>; /* milliseconds */ + polling-delay = <2500>; /* milliseconds */ + + /* sensor ID */ + thermal-sensors = <&adc-dummy 0>, /* pcb top edge */ + <&adc-dummy 1>, /* lcd */ + <&adc-dymmy 2>; /* back cover */ + /* + * An array of coefficients describing the sensor + * linear relation. E.g.: + * z = c1*x1 + c2*x2 + c3*x3 + */ + coefficients = <1200 -345 890>; + + trips { + /* Trips are based on resulting linear equation */ + cpu-trip: cpu-trip { + temperature = <60000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + gpu-trip: gpu-trip { + temperature = <55000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + } + lcd-trip: lcp-trip { + temperature = <53000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "passive"; + }; + crit-trip: crit-trip { + temperature = <68000>; /* millicelsius */ + hysteresis = <2000>; /* millicelsius */ + type = "critical"; + }; + }; + + cooling-maps { + map0 { + trip = <&cpu-trip>; + cooling-device = <&cpu0 0 2>; + contribution = <55>; + }; + map1 { + trip = <&gpu-trip>; + cooling-device = <&gpu0 0 2>; + contribution = <20>; + }; + map2 { + trip = <&lcd-trip>; + cooling-device = <&lcd0 5 10>; + contribution = <15>; + }; + }; + }; +}; + +The above example is a mix of previous examples, a sensor IP with several internal +sensors used to monitor different zones, one of them is composed by several sensors and +with different cooling devices. diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index f35a1f75b15b..a150f8d53322 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -29,6 +29,19 @@ config THERMAL_HWMON Say 'Y' here if you want all thermal sensors to have hwmon sysfs interface too. +config THERMAL_OF + bool + prompt "APIs to parse thermal data out of device tree" + depends on OF + default y + help + This options provides helpers to add the support to + read and parse thermal data definitions out of the + device tree blob. + + Say 'Y' here if you need to build thermal infrastructure + based on device tree. + choice prompt "Default Thermal governor" default THERMAL_DEFAULT_GOV_STEP_WISE diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 584b36319d51..4b03956b929c 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -7,6 +7,7 @@ thermal_sys-y += thermal_core.o # interface to/from other layers providing sensors thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o +thermal_sys-$(CONFIG_THERMAL_OF) += of-thermal.o # governors thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c new file mode 100644 index 000000000000..04b1be7fa018 --- /dev/null +++ b/drivers/thermal/of-thermal.c @@ -0,0 +1,849 @@ +/* + * of-thermal.c - Generic Thermal Management device tree support. + * + * Copyright (C) 2013 Texas Instruments + * Copyright (C) 2013 Eduardo Valentin + * + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "thermal_core.h" + +/*** Private data structures to represent thermal device tree data ***/ + +/** + * struct __thermal_trip - representation of a point in temperature domain + * @np: pointer to struct device_node that this trip point was created from + * @temperature: temperature value in miliCelsius + * @hysteresis: relative hysteresis in miliCelsius + * @type: trip point type + */ + +struct __thermal_trip { + struct device_node *np; + unsigned long int temperature; + unsigned long int hysteresis; + enum thermal_trip_type type; +}; + +/** + * struct __thermal_bind_param - a match between trip and cooling device + * @cooling_device: a pointer to identify the referred cooling device + * @trip_id: the trip point index + * @usage: the percentage (from 0 to 100) of cooling contribution + * @min: minimum cooling state used at this trip point + * @max: maximum cooling state used at this trip point + */ + +struct __thermal_bind_params { + struct device_node *cooling_device; + unsigned int trip_id; + unsigned int usage; + unsigned long min; + unsigned long max; +}; + +/** + * struct __thermal_zone - internal representation of a thermal zone + * @mode: current thermal zone device mode (enabled/disabled) + * @passive_delay: polling interval while passive cooling is activated + * @polling_delay: zone polling interval + * @ntrips: number of trip points + * @trips: an array of trip points (0..ntrips - 1) + * @num_tbps: number of thermal bind params + * @tbps: an array of thermal bind params (0..num_tbps - 1) + * @sensor_data: sensor private data used while reading temperature and trend + * @get_temp: sensor callback to read temperature + * @get_trend: sensor callback to read temperature trend + */ + +struct __thermal_zone { + enum thermal_device_mode mode; + int passive_delay; + int polling_delay; + + /* trip data */ + int ntrips; + struct __thermal_trip *trips; + + /* cooling binding data */ + int num_tbps; + struct __thermal_bind_params *tbps; + + /* sensor interface */ + void *sensor_data; + int (*get_temp)(void *, long *); + int (*get_trend)(void *, long *); +}; + +/*** DT thermal zone device callbacks ***/ + +static int of_thermal_get_temp(struct thermal_zone_device *tz, + unsigned long *temp) +{ + struct __thermal_zone *data = tz->devdata; + + if (!data->get_temp) + return -EINVAL; + + return data->get_temp(data->sensor_data, temp); +} + +static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip, + enum thermal_trend *trend) +{ + struct __thermal_zone *data = tz->devdata; + long dev_trend; + int r; + + if (!data->get_trend) + return -EINVAL; + + r = data->get_trend(data->sensor_data, &dev_trend); + if (r) + return r; + + /* TODO: These intervals might have some thresholds, but in core code */ + if (dev_trend > 0) + *trend = THERMAL_TREND_RAISING; + else if (dev_trend < 0) + *trend = THERMAL_TREND_DROPPING; + else + *trend = THERMAL_TREND_STABLE; + + return 0; +} + +static int of_thermal_bind(struct thermal_zone_device *thermal, + struct thermal_cooling_device *cdev) +{ + struct __thermal_zone *data = thermal->devdata; + int i; + + if (!data || IS_ERR(data)) + return -ENODEV; + + /* find where to bind */ + for (i = 0; i < data->num_tbps; i++) { + struct __thermal_bind_params *tbp = data->tbps + i; + + if (tbp->cooling_device == cdev->np) { + int ret; + + ret = thermal_zone_bind_cooling_device(thermal, + tbp->trip_id, cdev, + tbp->min, + tbp->max); + if (ret) + return ret; + } + } + + return 0; +} + +static int of_thermal_unbind(struct thermal_zone_device *thermal, + struct thermal_cooling_device *cdev) +{ + struct __thermal_zone *data = thermal->devdata; + int i; + + if (!data || IS_ERR(data)) + return -ENODEV; + + /* find where to unbind */ + for (i = 0; i < data->num_tbps; i++) { + struct __thermal_bind_params *tbp = data->tbps + i; + + if (tbp->cooling_device == cdev->np) { + int ret; + + ret = thermal_zone_unbind_cooling_device(thermal, + tbp->trip_id, cdev); + if (ret) + return ret; + } + } + + return 0; +} + +static int of_thermal_get_mode(struct thermal_zone_device *tz, + enum thermal_device_mode *mode) +{ + struct __thermal_zone *data = tz->devdata; + + *mode = data->mode; + + return 0; +} + +static int of_thermal_set_mode(struct thermal_zone_device *tz, + enum thermal_device_mode mode) +{ + struct __thermal_zone *data = tz->devdata; + + mutex_lock(&tz->lock); + + if (mode == THERMAL_DEVICE_ENABLED) + tz->polling_delay = data->polling_delay; + else + tz->polling_delay = 0; + + mutex_unlock(&tz->lock); + + data->mode = mode; + thermal_zone_device_update(tz); + + return 0; +} + +static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip, + enum thermal_trip_type *type) +{ + struct __thermal_zone *data = tz->devdata; + + if (trip >= data->ntrips || trip < 0) + return -EDOM; + + *type = data->trips[trip].type; + + return 0; +} + +static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip, + unsigned long *temp) +{ + struct __thermal_zone *data = tz->devdata; + + if (trip >= data->ntrips || trip < 0) + return -EDOM; + + *temp = data->trips[trip].temperature; + + return 0; +} + +static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip, + unsigned long temp) +{ + struct __thermal_zone *data = tz->devdata; + + if (trip >= data->ntrips || trip < 0) + return -EDOM; + + /* thermal framework should take care of data->mask & (1 << trip) */ + data->trips[trip].temperature = temp; + + return 0; +} + +static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip, + unsigned long *hyst) +{ + struct __thermal_zone *data = tz->devdata; + + if (trip >= data->ntrips || trip < 0) + return -EDOM; + + *hyst = data->trips[trip].hysteresis; + + return 0; +} + +static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip, + unsigned long hyst) +{ + struct __thermal_zone *data = tz->devdata; + + if (trip >= data->ntrips || trip < 0) + return -EDOM; + + /* thermal framework should take care of data->mask & (1 << trip) */ + data->trips[trip].hysteresis = hyst; + + return 0; +} + +static int of_thermal_get_crit_temp(struct thermal_zone_device *tz, + unsigned long *temp) +{ + struct __thermal_zone *data = tz->devdata; + int i; + + for (i = 0; i < data->ntrips; i++) + if (data->trips[i].type == THERMAL_TRIP_CRITICAL) { + *temp = data->trips[i].temperature; + return 0; + } + + return -EINVAL; +} + +static struct thermal_zone_device_ops of_thermal_ops = { + .get_mode = of_thermal_get_mode, + .set_mode = of_thermal_set_mode, + + .get_trip_type = of_thermal_get_trip_type, + .get_trip_temp = of_thermal_get_trip_temp, + .set_trip_temp = of_thermal_set_trip_temp, + .get_trip_hyst = of_thermal_get_trip_hyst, + .set_trip_hyst = of_thermal_set_trip_hyst, + .get_crit_temp = of_thermal_get_crit_temp, + + .bind = of_thermal_bind, + .unbind = of_thermal_unbind, +}; + +/*** sensor API ***/ + +static struct thermal_zone_device * +thermal_zone_of_add_sensor(struct device_node *zone, + struct device_node *sensor, void *data, + int (*get_temp)(void *, long *), + int (*get_trend)(void *, long *)) +{ + struct thermal_zone_device *tzd; + struct __thermal_zone *tz; + + tzd = thermal_zone_get_zone_by_name(zone->name); + if (IS_ERR(tzd)) + return ERR_PTR(-EPROBE_DEFER); + + tz = tzd->devdata; + + mutex_lock(&tzd->lock); + tz->get_temp = get_temp; + tz->get_trend = get_trend; + tz->sensor_data = data; + + tzd->ops->get_temp = of_thermal_get_temp; + tzd->ops->get_trend = of_thermal_get_trend; + mutex_unlock(&tzd->lock); + + return tzd; +} + +/** + * thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone + * @dev: a valid struct device pointer of a sensor device. Must contain + * a valid .of_node, for the sensor node. + * @sensor_id: a sensor identifier, in case the sensor IP has more + * than one sensors + * @data: a private pointer (owned by the caller) that will be passed + * back, when a temperature reading is needed. + * @get_temp: a pointer to a function that reads the sensor temperature. + * @get_trend: a pointer to a function that reads the sensor temperature trend. + * + * This function will search the list of thermal zones described in device + * tree and look for the zone that refer to the sensor device pointed by + * @dev->of_node as temperature providers. For the zone pointing to the + * sensor node, the sensor will be added to the DT thermal zone device. + * + * The thermal zone temperature is provided by the @get_temp function + * pointer. When called, it will have the private pointer @data back. + * + * The thermal zone temperature trend is provided by the @get_trend function + * pointer. When called, it will have the private pointer @data back. + * + * TODO: + * 01 - This function must enqueue the new sensor instead of using + * it as the only source of temperature values. + * + * 02 - There must be a way to match the sensor with all thermal zones + * that refer to it. + * + * Return: On success returns a valid struct thermal_zone_device, + * otherwise, it returns a corresponding ERR_PTR(). Caller must + * check the return value with help of IS_ERR() helper. + */ +struct thermal_zone_device * +thermal_zone_of_sensor_register(struct device *dev, int sensor_id, + void *data, int (*get_temp)(void *, long *), + int (*get_trend)(void *, long *)) +{ + struct device_node *np, *child, *sensor_np; + + np = of_find_node_by_name(NULL, "thermal-zones"); + if (!np) + return ERR_PTR(-ENODEV); + + if (!dev || !dev->of_node) + return ERR_PTR(-EINVAL); + + sensor_np = dev->of_node; + + for_each_child_of_node(np, child) { + struct of_phandle_args sensor_specs; + int ret, id; + + /* For now, thermal framework supports only 1 sensor per zone */ + ret = of_parse_phandle_with_args(child, "thermal-sensors", + "#thermal-sensor-cells", + 0, &sensor_specs); + if (ret) + continue; + + if (sensor_specs.args_count >= 1) { + id = sensor_specs.args[0]; + WARN(sensor_specs.args_count > 1, + "%s: too many cells in sensor specifier %d\n", + sensor_specs.np->name, sensor_specs.args_count); + } else { + id = 0; + } + + if (sensor_specs.np == sensor_np && id == sensor_id) { + of_node_put(np); + return thermal_zone_of_add_sensor(child, sensor_np, + data, + get_temp, + get_trend); + } + } + of_node_put(np); + + return ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_register); + +/** + * thermal_zone_of_sensor_unregister - unregisters a sensor from a DT thermal zone + * @dev: a valid struct device pointer of a sensor device. Must contain + * a valid .of_node, for the sensor node. + * @tzd: a pointer to struct thermal_zone_device where the sensor is registered. + * + * This function removes the sensor callbacks and private data from the + * thermal zone device registered with thermal_zone_of_sensor_register() + * API. It will also silent the zone by remove the .get_temp() and .get_trend() + * thermal zone device callbacks. + * + * TODO: When the support to several sensors per zone is added, this + * function must search the sensor list based on @dev parameter. + * + */ +void thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tzd) +{ + struct __thermal_zone *tz; + + if (!dev || !tzd || !tzd->devdata) + return; + + tz = tzd->devdata; + + /* no __thermal_zone, nothing to be done */ + if (!tz) + return; + + mutex_lock(&tzd->lock); + tzd->ops->get_temp = NULL; + tzd->ops->get_trend = NULL; + + tz->get_temp = NULL; + tz->get_trend = NULL; + tz->sensor_data = NULL; + mutex_unlock(&tzd->lock); +} +EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister); + +/*** functions parsing device tree nodes ***/ + +/** + * thermal_of_populate_bind_params - parse and fill cooling map data + * @np: DT node containing a cooling-map node + * @__tbp: data structure to be filled with cooling map info + * @trips: array of thermal zone trip points + * @ntrips: number of trip points inside trips. + * + * This function parses a cooling-map type of node represented by + * @np parameter and fills the read data into @__tbp data structure. + * It needs the already parsed array of trip points of the thermal zone + * in consideration. + * + * Return: 0 on success, proper error code otherwise + */ +static int thermal_of_populate_bind_params(struct device_node *np, + struct __thermal_bind_params *__tbp, + struct __thermal_trip *trips, + int ntrips) +{ + struct of_phandle_args cooling_spec; + struct device_node *trip; + int ret, i; + u32 prop; + + /* Default weight. Usage is optional */ + __tbp->usage = 0; + ret = of_property_read_u32(np, "contribution", &prop); + if (ret == 0) + __tbp->usage = prop; + + trip = of_parse_phandle(np, "trip", 0); + if (!trip) { + pr_err("missing trip property\n"); + return -ENODEV; + } + + /* match using device_node */ + for (i = 0; i < ntrips; i++) + if (trip == trips[i].np) { + __tbp->trip_id = i; + break; + } + + if (i == ntrips) { + ret = -ENODEV; + goto end; + } + + ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells", + 0, &cooling_spec); + if (ret < 0) { + pr_err("missing cooling_device property\n"); + goto end; + } + __tbp->cooling_device = cooling_spec.np; + if (cooling_spec.args_count >= 2) { /* at least min and max */ + __tbp->min = cooling_spec.args[0]; + __tbp->max = cooling_spec.args[1]; + } else { + pr_err("wrong reference to cooling device, missing limits\n"); + } + +end: + of_node_put(trip); + + return ret; +} + +/** + * It maps 'enum thermal_trip_type' found in include/linux/thermal.h + * into the device tree binding of 'trip', property type. + */ +static const char * const trip_types[] = { + [THERMAL_TRIP_ACTIVE] = "active", + [THERMAL_TRIP_PASSIVE] = "passive", + [THERMAL_TRIP_HOT] = "hot", + [THERMAL_TRIP_CRITICAL] = "critical", +}; + +/** + * thermal_of_get_trip_type - Get phy mode for given device_node + * @np: Pointer to the given device_node + * @type: Pointer to resulting trip type + * + * The function gets trip type string from property 'type', + * and store its index in trip_types table in @type, + * + * Return: 0 on success, or errno in error case. + */ +static int thermal_of_get_trip_type(struct device_node *np, + enum thermal_trip_type *type) +{ + const char *t; + int err, i; + + err = of_property_read_string(np, "type", &t); + if (err < 0) + return err; + + for (i = 0; i < ARRAY_SIZE(trip_types); i++) + if (!strcasecmp(t, trip_types[i])) { + *type = i; + return 0; + } + + return -ENODEV; +} + +/** + * thermal_of_populate_trip - parse and fill one trip point data + * @np: DT node containing a trip point node + * @trip: trip point data structure to be filled up + * + * This function parses a trip point type of node represented by + * @np parameter and fills the read data into @trip data structure. + * + * Return: 0 on success, proper error code otherwise + */ +static int thermal_of_populate_trip(struct device_node *np, + struct __thermal_trip *trip) +{ + int prop; + int ret; + + ret = of_property_read_u32(np, "temperature", &prop); + if (ret < 0) { + pr_err("missing temperature property\n"); + return ret; + } + trip->temperature = prop; + + ret = of_property_read_u32(np, "hysteresis", &prop); + if (ret < 0) { + pr_err("missing hysteresis property\n"); + return ret; + } + trip->hysteresis = prop; + + ret = thermal_of_get_trip_type(np, &trip->type); + if (ret < 0) { + pr_err("wrong trip type property\n"); + return ret; + } + + /* Required for cooling map matching */ + trip->np = np; + + return 0; +} + +/** + * thermal_of_build_thermal_zone - parse and fill one thermal zone data + * @np: DT node containing a thermal zone node + * + * This function parses a thermal zone type of node represented by + * @np parameter and fills the read data into a __thermal_zone data structure + * and return this pointer. + * + * TODO: Missing properties to parse: thermal-sensor-names and coefficients + * + * Return: On success returns a valid struct __thermal_zone, + * otherwise, it returns a corresponding ERR_PTR(). Caller must + * check the return value with help of IS_ERR() helper. + */ +static struct __thermal_zone * +thermal_of_build_thermal_zone(struct device_node *np) +{ + struct device_node *child = NULL, *gchild; + struct __thermal_zone *tz; + int ret, i; + u32 prop; + + if (!np) { + pr_err("no thermal zone np\n"); + return ERR_PTR(-EINVAL); + } + + tz = kzalloc(sizeof(*tz), GFP_KERNEL); + if (!tz) + return ERR_PTR(-ENOMEM); + + ret = of_property_read_u32(np, "polling-delay-passive", &prop); + if (ret < 0) { + pr_err("missing polling-delay-passive property\n"); + goto free_tz; + } + tz->passive_delay = prop; + + ret = of_property_read_u32(np, "polling-delay", &prop); + if (ret < 0) { + pr_err("missing polling-delay property\n"); + goto free_tz; + } + tz->polling_delay = prop; + + /* trips */ + child = of_get_child_by_name(np, "trips"); + + /* No trips provided */ + if (!child) + goto finish; + + tz->ntrips = of_get_child_count(child); + if (tz->ntrips == 0) /* must have at least one child */ + goto finish; + + tz->trips = kzalloc(tz->ntrips * sizeof(*tz->trips), GFP_KERNEL); + if (!tz->trips) { + ret = -ENOMEM; + goto free_tz; + } + + i = 0; + for_each_child_of_node(child, gchild) { + ret = thermal_of_populate_trip(gchild, &tz->trips[i++]); + if (ret) + goto free_trips; + } + + of_node_put(child); + + /* cooling-maps */ + child = of_get_child_by_name(np, "cooling-maps"); + + /* cooling-maps not provided */ + if (!child) + goto finish; + + tz->num_tbps = of_get_child_count(child); + if (tz->num_tbps == 0) + goto finish; + + tz->tbps = kzalloc(tz->num_tbps * sizeof(*tz->tbps), GFP_KERNEL); + if (!tz->tbps) { + ret = -ENOMEM; + goto free_trips; + } + + i = 0; + for_each_child_of_node(child, gchild) + ret = thermal_of_populate_bind_params(gchild, &tz->tbps[i++], + tz->trips, tz->ntrips); + if (ret) + goto free_tbps; + +finish: + of_node_put(child); + tz->mode = THERMAL_DEVICE_DISABLED; + + return tz; + +free_tbps: + kfree(tz->tbps); +free_trips: + kfree(tz->trips); +free_tz: + kfree(tz); + of_node_put(child); + + return ERR_PTR(ret); +} + +static inline void of_thermal_free_zone(struct __thermal_zone *tz) +{ + kfree(tz->tbps); + kfree(tz->trips); + kfree(tz); +} + +/** + * of_parse_thermal_zones - parse device tree thermal data + * + * Initialization function that can be called by machine initialization + * code to parse thermal data and populate the thermal framework + * with hardware thermal zones info. This function only parses thermal zones. + * Cooling devices and sensor devices nodes are supposed to be parsed + * by their respective drivers. + * + * Return: 0 on success, proper error code otherwise + * + */ +int __init of_parse_thermal_zones(void) +{ + struct device_node *np, *child; + struct __thermal_zone *tz; + struct thermal_zone_device_ops *ops; + + np = of_find_node_by_name(NULL, "thermal-zones"); + if (!np) { + pr_debug("unable to find thermal zones\n"); + return 0; /* Run successfully on systems without thermal DT */ + } + + for_each_child_of_node(np, child) { + struct thermal_zone_device *zone; + struct thermal_zone_params *tzp; + + tz = thermal_of_build_thermal_zone(child); + if (IS_ERR(tz)) { + pr_err("failed to build thermal zone %s: %ld\n", + child->name, + PTR_ERR(tz)); + continue; + } + + ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL); + if (!ops) + goto exit_free; + + tzp = kzalloc(sizeof(*tzp), GFP_KERNEL); + if (!tzp) { + kfree(ops); + goto exit_free; + } + + /* No hwmon because there might be hwmon drivers registering */ + tzp->no_hwmon = true; + + zone = thermal_zone_device_register(child->name, tz->ntrips, + 0, tz, + ops, tzp, + tz->passive_delay, + tz->polling_delay); + if (IS_ERR(zone)) { + pr_err("Failed to build %s zone %ld\n", child->name, + PTR_ERR(zone)); + kfree(tzp); + kfree(ops); + of_thermal_free_zone(tz); + /* attempting to build remaining zones still */ + } + } + + return 0; + +exit_free: + of_thermal_free_zone(tz); + + /* no memory available, so free what we have built */ + of_thermal_destroy_zones(); + + return -ENOMEM; +} + +/** + * of_thermal_destroy_zones - remove all zones parsed and allocated resources + * + * Finds all zones parsed and added to the thermal framework and remove them + * from the system, together with their resources. + * + */ +void of_thermal_destroy_zones(void) +{ + struct device_node *np, *child; + + np = of_find_node_by_name(NULL, "thermal-zones"); + if (!np) { + pr_err("unable to find thermal zones\n"); + return; + } + + for_each_child_of_node(np, child) { + struct thermal_zone_device *zone; + + zone = thermal_zone_get_zone_by_name(child->name); + if (IS_ERR(zone)) + continue; + + thermal_zone_device_unregister(zone); + kfree(zone->tzp); + kfree(zone->ops); + of_thermal_free_zone(zone->devdata); + } +} diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 0e43dc208fc6..3392fcb92796 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1373,7 +1373,7 @@ static void remove_trip_attrs(struct thermal_zone_device *tz) */ struct thermal_zone_device *thermal_zone_device_register(const char *type, int trips, int mask, void *devdata, - const struct thermal_zone_device_ops *ops, + struct thermal_zone_device_ops *ops, const struct thermal_zone_params *tzp, int passive_delay, int polling_delay) { @@ -1746,8 +1746,14 @@ static int __init thermal_init(void) if (result) goto unregister_class; + result = of_parse_thermal_zones(); + if (result) + goto exit_netlink; + return 0; +exit_netlink: + genetlink_exit(); unregister_governors: thermal_unregister_governors(); unregister_class: @@ -1763,6 +1769,7 @@ error: static void __exit thermal_exit(void) { + of_thermal_destroy_zones(); genetlink_exit(); class_unregister(&thermal_class); thermal_unregister_governors(); diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index 7cf2f6626251..3db339fb636f 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -77,4 +77,13 @@ static inline int thermal_gov_user_space_register(void) { return 0; } static inline void thermal_gov_user_space_unregister(void) {} #endif /* CONFIG_THERMAL_GOV_USER_SPACE */ +/* device tree support */ +#ifdef CONFIG_THERMAL_OF +int of_parse_thermal_zones(void); +void of_thermal_destroy_zones(void); +#else +static inline int of_parse_thermal_zones(void) { return 0; } +static inline void of_thermal_destroy_zones(void) { } +#endif + #endif /* __THERMAL_CORE_H__ */ diff --git a/include/dt-bindings/thermal/thermal.h b/include/dt-bindings/thermal/thermal.h new file mode 100644 index 000000000000..59822a995858 --- /dev/null +++ b/include/dt-bindings/thermal/thermal.h @@ -0,0 +1,17 @@ +/* + * This header provides constants for most thermal bindings. + * + * Copyright (C) 2013 Texas Instruments + * Eduardo Valentin + * + * GPLv2 only + */ + +#ifndef _DT_BINDINGS_THERMAL_THERMAL_H +#define _DT_BINDINGS_THERMAL_THERMAL_H + +/* On cooling devices upper and lower limits */ +#define THERMAL_NO_LIMIT (-1UL) + +#endif + diff --git a/include/linux/thermal.h b/include/linux/thermal.h index b268d3cf7ae3..b780c5b27122 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -143,6 +143,7 @@ struct thermal_cooling_device { int id; char type[THERMAL_NAME_LENGTH]; struct device device; + struct device_node *np; void *devdata; const struct thermal_cooling_device_ops *ops; bool updated; /* true if the cooling device does not need update */ @@ -172,7 +173,7 @@ struct thermal_zone_device { int emul_temperature; int passive; unsigned int forced_passive; - const struct thermal_zone_device_ops *ops; + struct thermal_zone_device_ops *ops; const struct thermal_zone_params *tzp; struct thermal_governor *governor; struct list_head thermal_instances; @@ -242,8 +243,31 @@ struct thermal_genl_event { }; /* Function declarations */ +#ifdef CONFIG_THERMAL_OF +struct thermal_zone_device * +thermal_zone_of_sensor_register(struct device *dev, int id, + void *data, int (*get_temp)(void *, long *), + int (*get_trend)(void *, long *)); +void thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tz); +#else +static inline struct thermal_zone_device * +thermal_zone_of_sensor_register(struct device *dev, int id, + void *data, int (*get_temp)(void *, long *), + int (*get_trend)(void *, long *)) +{ + return NULL; +} + +static inline +void thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tz) +{ +} + +#endif struct thermal_zone_device *thermal_zone_device_register(const char *, int, int, - void *, const struct thermal_zone_device_ops *, + void *, struct thermal_zone_device_ops *, const struct thermal_zone_params *, int, int); void thermal_zone_device_unregister(struct thermal_zone_device *); -- cgit v1.2.3-59-g8ed1b From a116b5d44f144586ef03a93f14ddc63f4a85e906 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 26 Sep 2013 15:55:01 -0400 Subject: thermal: core: introduce thermal_of_cooling_device_register This patch adds a new API to allow registering cooling devices in the thermal framework derived from device tree nodes. This API links the cooling device with the device tree node so that binding with thermal zones is possible, given that thermal zones are pointing to cooling device device tree nodes. Cc: Zhang Rui Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Eduardo Valentin --- drivers/thermal/thermal_core.c | 58 +++++++++++++++++++++++++++++++++++++++--- include/linux/thermal.h | 4 +++ 2 files changed, 58 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 3392fcb92796..e381d521c355 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -1055,7 +1056,8 @@ static struct class thermal_class = { }; /** - * thermal_cooling_device_register() - register a new thermal cooling device + * __thermal_cooling_device_register() - register a new thermal cooling device + * @np: a pointer to a device tree node. * @type: the thermal cooling device type. * @devdata: device private data. * @ops: standard thermal cooling devices callbacks. @@ -1063,13 +1065,16 @@ static struct class thermal_class = { * This interface function adds a new thermal cooling device (fan/processor/...) * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself * to all the thermal zone devices registered at the same time. + * It also gives the opportunity to link the cooling device to a device tree + * node, so that it can be bound to a thermal zone created out of device tree. * * Return: a pointer to the created struct thermal_cooling_device or an * ERR_PTR. Caller must check return value with IS_ERR*() helpers. */ -struct thermal_cooling_device * -thermal_cooling_device_register(char *type, void *devdata, - const struct thermal_cooling_device_ops *ops) +static struct thermal_cooling_device * +__thermal_cooling_device_register(struct device_node *np, + char *type, void *devdata, + const struct thermal_cooling_device_ops *ops) { struct thermal_cooling_device *cdev; int result; @@ -1094,6 +1099,7 @@ thermal_cooling_device_register(char *type, void *devdata, strlcpy(cdev->type, type ? : "", sizeof(cdev->type)); mutex_init(&cdev->lock); INIT_LIST_HEAD(&cdev->thermal_instances); + cdev->np = np; cdev->ops = ops; cdev->updated = true; cdev->device.class = &thermal_class; @@ -1136,8 +1142,52 @@ unregister: device_unregister(&cdev->device); return ERR_PTR(result); } + +/** + * thermal_cooling_device_register() - register a new thermal cooling device + * @type: the thermal cooling device type. + * @devdata: device private data. + * @ops: standard thermal cooling devices callbacks. + * + * This interface function adds a new thermal cooling device (fan/processor/...) + * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself + * to all the thermal zone devices registered at the same time. + * + * Return: a pointer to the created struct thermal_cooling_device or an + * ERR_PTR. Caller must check return value with IS_ERR*() helpers. + */ +struct thermal_cooling_device * +thermal_cooling_device_register(char *type, void *devdata, + const struct thermal_cooling_device_ops *ops) +{ + return __thermal_cooling_device_register(NULL, type, devdata, ops); +} EXPORT_SYMBOL_GPL(thermal_cooling_device_register); +/** + * thermal_of_cooling_device_register() - register an OF thermal cooling device + * @np: a pointer to a device tree node. + * @type: the thermal cooling device type. + * @devdata: device private data. + * @ops: standard thermal cooling devices callbacks. + * + * This function will register a cooling device with device tree node reference. + * This interface function adds a new thermal cooling device (fan/processor/...) + * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself + * to all the thermal zone devices registered at the same time. + * + * Return: a pointer to the created struct thermal_cooling_device or an + * ERR_PTR. Caller must check return value with IS_ERR*() helpers. + */ +struct thermal_cooling_device * +thermal_of_cooling_device_register(struct device_node *np, + char *type, void *devdata, + const struct thermal_cooling_device_ops *ops) +{ + return __thermal_cooling_device_register(np, type, devdata, ops); +} +EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register); + /** * thermal_cooling_device_unregister - removes the registered thermal cooling device * @cdev: the thermal cooling device to remove. diff --git a/include/linux/thermal.h b/include/linux/thermal.h index b780c5b27122..f7e11c7ea7d9 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -25,6 +25,7 @@ #ifndef __THERMAL_H__ #define __THERMAL_H__ +#include #include #include #include @@ -280,6 +281,9 @@ void thermal_zone_device_update(struct thermal_zone_device *); struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, const struct thermal_cooling_device_ops *); +struct thermal_cooling_device * +thermal_of_cooling_device_register(struct device_node *np, char *, void *, + const struct thermal_cooling_device_ops *); void thermal_cooling_device_unregister(struct thermal_cooling_device *); struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name); int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp); -- cgit v1.2.3-59-g8ed1b From 39d99cff76bf2992fd6dd4b1fc62da139e62e90c Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 12 Sep 2013 19:26:45 -0400 Subject: thermal: cpu_cooling: introduce of_cpufreq_cooling_register This patch introduces an API to register cpufreq cooling device based on device tree node. The registration via device tree node differs from normal registration due to the fact that it is needed to fill the device_node structure in order to be able to match the cooling devices with trip points. Cc: Zhang Rui Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Eduardo Valentin --- drivers/thermal/Kconfig | 1 + drivers/thermal/cpu_cooling.c | 56 ++++++++++++++++++++++++++++++++++++++----- include/linux/cpu_cooling.h | 25 +++++++++++++++++++ 3 files changed, 76 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index a150f8d53322..3feb5377fbf6 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -92,6 +92,7 @@ config THERMAL_GOV_USER_SPACE config CPU_THERMAL bool "generic cpu cooling support" depends on CPU_FREQ + depends on THERMAL_OF help This implements the generic cpu cooling mechanism through frequency reduction. An ACPI version of this already exists diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 02a46f23d14c..a6cb5531403f 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -417,18 +417,21 @@ static struct notifier_block thermal_cpufreq_notifier_block = { }; /** - * cpufreq_cooling_register - function to create cpufreq cooling device. + * __cpufreq_cooling_register - helper function to create cpufreq cooling device + * @np: a valid struct device_node to the cooling device device tree node * @clip_cpus: cpumask of cpus where the frequency constraints will happen. * * This interface function registers the cpufreq cooling device with the name * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq - * cooling devices. + * cooling devices. It also gives the opportunity to link the cooling device + * with a device tree node, in order to bind it via the thermal DT code. * * Return: a valid struct thermal_cooling_device pointer on success, * on failure, it returns a corresponding ERR_PTR(). */ -struct thermal_cooling_device * -cpufreq_cooling_register(const struct cpumask *clip_cpus) +static struct thermal_cooling_device * +__cpufreq_cooling_register(struct device_node *np, + const struct cpumask *clip_cpus) { struct thermal_cooling_device *cool_dev; struct cpufreq_cooling_device *cpufreq_dev = NULL; @@ -467,8 +470,8 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus) snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", cpufreq_dev->id); - cool_dev = thermal_cooling_device_register(dev_name, cpufreq_dev, - &cpufreq_cooling_ops); + cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev, + &cpufreq_cooling_ops); if (IS_ERR(cool_dev)) { release_idr(&cpufreq_idr, cpufreq_dev->id); kfree(cpufreq_dev); @@ -488,8 +491,49 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus) return cool_dev; } + +/** + * cpufreq_cooling_register - function to create cpufreq cooling device. + * @clip_cpus: cpumask of cpus where the frequency constraints will happen. + * + * This interface function registers the cpufreq cooling device with the name + * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq + * cooling devices. + * + * Return: a valid struct thermal_cooling_device pointer on success, + * on failure, it returns a corresponding ERR_PTR(). + */ +struct thermal_cooling_device * +cpufreq_cooling_register(const struct cpumask *clip_cpus) +{ + return __cpufreq_cooling_register(NULL, clip_cpus); +} EXPORT_SYMBOL_GPL(cpufreq_cooling_register); +/** + * of_cpufreq_cooling_register - function to create cpufreq cooling device. + * @np: a valid struct device_node to the cooling device device tree node + * @clip_cpus: cpumask of cpus where the frequency constraints will happen. + * + * This interface function registers the cpufreq cooling device with the name + * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq + * cooling devices. Using this API, the cpufreq cooling device will be + * linked to the device tree node provided. + * + * Return: a valid struct thermal_cooling_device pointer on success, + * on failure, it returns a corresponding ERR_PTR(). + */ +struct thermal_cooling_device * +of_cpufreq_cooling_register(struct device_node *np, + const struct cpumask *clip_cpus) +{ + if (!np) + return ERR_PTR(-EINVAL); + + return __cpufreq_cooling_register(np, clip_cpus); +} +EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register); + /** * cpufreq_cooling_unregister - function to remove cpufreq cooling device. * @cdev: thermal cooling device pointer. diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h index a5d52eea8232..c303d383def1 100644 --- a/include/linux/cpu_cooling.h +++ b/include/linux/cpu_cooling.h @@ -24,6 +24,7 @@ #ifndef __CPU_COOLING_H__ #define __CPU_COOLING_H__ +#include #include #include @@ -35,6 +36,24 @@ struct thermal_cooling_device * cpufreq_cooling_register(const struct cpumask *clip_cpus); +/** + * of_cpufreq_cooling_register - create cpufreq cooling device based on DT. + * @np: a valid struct device_node to the cooling device device tree node. + * @clip_cpus: cpumask of cpus where the frequency constraints will happen + */ +#ifdef CONFIG_THERMAL_OF +struct thermal_cooling_device * +of_cpufreq_cooling_register(struct device_node *np, + const struct cpumask *clip_cpus); +#else +static inline struct thermal_cooling_device * +of_cpufreq_cooling_register(struct device_node *np, + const struct cpumask *clip_cpus) +{ + return NULL; +} +#endif + /** * cpufreq_cooling_unregister - function to remove cpufreq cooling device. * @cdev: thermal cooling device pointer. @@ -48,6 +67,12 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus) { return NULL; } +static inline struct thermal_cooling_device * +of_cpufreq_cooling_register(struct device_node *np, + const struct cpumask *clip_cpus) +{ + return NULL; +} static inline void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) { -- cgit v1.2.3-59-g8ed1b From 9fb1f39eb2d6707d265087ee186376e24995f55a Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 4 Dec 2013 14:42:46 +0100 Subject: gpio/pinctrl: make gpio_chip members typed boolean This switches the two members of struct gpio_chip that were defined as unsigned foo:1 to bool, because that is indeed what they are. Switch all users in the gpio and pinctrl subsystems to assign these values with true/false instead of 0/1. The users outside these subsystems will survive since true/false is 1/0, atleast we set some kind of more strict typing example. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-74x164.c | 2 +- drivers/gpio/gpio-adnp.c | 2 +- drivers/gpio/gpio-adp5520.c | 2 +- drivers/gpio/gpio-adp5588.c | 2 +- drivers/gpio/gpio-arizona.c | 2 +- drivers/gpio/gpio-bt8xx.c | 2 +- drivers/gpio/gpio-da9052.c | 2 +- drivers/gpio/gpio-da9055.c | 2 +- drivers/gpio/gpio-ich.c | 2 +- drivers/gpio/gpio-intel-mid.c | 2 +- drivers/gpio/gpio-kempld.c | 2 +- drivers/gpio/gpio-ks8695.c | 2 +- drivers/gpio/gpio-lpc32xx.c | 12 ++++++------ drivers/gpio/gpio-lynxpoint.c | 2 +- drivers/gpio/gpio-max730x.c | 2 +- drivers/gpio/gpio-max732x.c | 2 +- drivers/gpio/gpio-mc33880.c | 2 +- drivers/gpio/gpio-mc9s08dz60.c | 2 +- drivers/gpio/gpio-mcp23s08.c | 2 +- drivers/gpio/gpio-ml-ioh.c | 2 +- drivers/gpio/gpio-msic.c | 2 +- drivers/gpio/gpio-mvebu.c | 2 +- drivers/gpio/gpio-octeon.c | 2 +- drivers/gpio/gpio-palmas.c | 2 +- drivers/gpio/gpio-pca953x.c | 2 +- drivers/gpio/gpio-pcf857x.c | 2 +- drivers/gpio/gpio-pch.c | 2 +- drivers/gpio/gpio-rc5t583.c | 2 +- drivers/gpio/gpio-sta2x11.c | 2 +- drivers/gpio/gpio-stmpe.c | 2 +- drivers/gpio/gpio-sx150x.c | 2 +- drivers/gpio/gpio-tb10x.c | 2 +- drivers/gpio/gpio-tc3589x.c | 2 +- drivers/gpio/gpio-timberdale.c | 2 +- drivers/gpio/gpio-tnetv107x.c | 2 +- drivers/gpio/gpio-tps6586x.c | 2 +- drivers/gpio/gpio-tps65910.c | 2 +- drivers/gpio/gpio-tps65912.c | 2 +- drivers/gpio/gpio-twl4030.c | 2 +- drivers/gpio/gpio-twl6040.c | 2 +- drivers/gpio/gpio-ucb1400.c | 2 +- drivers/gpio/gpio-viperboard.c | 4 ++-- drivers/gpio/gpio-vx855.c | 2 +- drivers/gpio/gpio-wm831x.c | 2 +- drivers/gpio/gpio-wm8350.c | 2 +- drivers/gpio/gpio-wm8994.c | 2 +- drivers/gpio/gpiolib.c | 2 +- drivers/pinctrl/pinctrl-as3722.c | 2 +- drivers/pinctrl/pinctrl-at91.c | 2 +- drivers/pinctrl/pinctrl-baytrail.c | 2 +- drivers/pinctrl/pinctrl-bcm2835.c | 2 +- drivers/pinctrl/pinctrl-nomadik.c | 2 +- drivers/pinctrl/pinctrl-sunxi.c | 2 +- drivers/pinctrl/vt8500/pinctrl-wmt.c | 2 +- include/linux/gpio/driver.h | 9 +++++---- 55 files changed, 65 insertions(+), 64 deletions(-) (limited to 'include/linux') diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index 1e04bf91328d..ddb831232407 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -159,7 +159,7 @@ static int gen_74x164_probe(struct spi_device *spi) goto exit_destroy; } - chip->gpio_chip.can_sleep = 1; + chip->gpio_chip.can_sleep = true; chip->gpio_chip.dev = &spi->dev; chip->gpio_chip.owner = THIS_MODULE; diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c index b204033acaeb..030a3897d9f7 100644 --- a/drivers/gpio/gpio-adnp.c +++ b/drivers/gpio/gpio-adnp.c @@ -260,7 +260,7 @@ static int adnp_gpio_setup(struct adnp *adnp, unsigned int num_gpios) chip->direction_output = adnp_gpio_direction_output; chip->get = adnp_gpio_get; chip->set = adnp_gpio_set; - chip->can_sleep = 1; + chip->can_sleep = true; if (IS_ENABLED(CONFIG_DEBUG_FS)) chip->dbg_show = adnp_gpio_dbg_show; diff --git a/drivers/gpio/gpio-adp5520.c b/drivers/gpio/gpio-adp5520.c index 084337d5514d..613265944e2e 100644 --- a/drivers/gpio/gpio-adp5520.c +++ b/drivers/gpio/gpio-adp5520.c @@ -127,7 +127,7 @@ static int adp5520_gpio_probe(struct platform_device *pdev) gc->direction_output = adp5520_gpio_direction_output; gc->get = adp5520_gpio_get_value; gc->set = adp5520_gpio_set_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = pdata->gpio_start; gc->ngpio = gpios; diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index 90fc4c99c024..3f190e68f973 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -380,7 +380,7 @@ static int adp5588_gpio_probe(struct i2c_client *client, gc->direction_output = adp5588_gpio_direction_output; gc->get = adp5588_gpio_get_value; gc->set = adp5588_gpio_set_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = pdata->gpio_start; gc->ngpio = ADP5588_MAXGPIO; diff --git a/drivers/gpio/gpio-arizona.c b/drivers/gpio/gpio-arizona.c index dceb5dcf9d16..29bdff558981 100644 --- a/drivers/gpio/gpio-arizona.c +++ b/drivers/gpio/gpio-arizona.c @@ -91,7 +91,7 @@ static struct gpio_chip template_chip = { .get = arizona_gpio_get, .direction_output = arizona_gpio_direction_out, .set = arizona_gpio_set, - .can_sleep = 1, + .can_sleep = true, }; static int arizona_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-bt8xx.c b/drivers/gpio/gpio-bt8xx.c index c5c356b7f2ce..ecb3ca2d1d10 100644 --- a/drivers/gpio/gpio-bt8xx.c +++ b/drivers/gpio/gpio-bt8xx.c @@ -169,7 +169,7 @@ static void bt8xxgpio_gpio_setup(struct bt8xxgpio *bg) c->dbg_show = NULL; c->base = modparam_gpiobase; c->ngpio = BT8XXGPIO_NR_GPIOS; - c->can_sleep = 0; + c->can_sleep = false; } static int bt8xxgpio_probe(struct pci_dev *dev, diff --git a/drivers/gpio/gpio-da9052.c b/drivers/gpio/gpio-da9052.c index 9b77dc05d4ad..416cdf786b05 100644 --- a/drivers/gpio/gpio-da9052.c +++ b/drivers/gpio/gpio-da9052.c @@ -200,7 +200,7 @@ static struct gpio_chip reference_gp = { .direction_input = da9052_gpio_direction_input, .direction_output = da9052_gpio_direction_output, .to_irq = da9052_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, .ngpio = 16, .base = -1, }; diff --git a/drivers/gpio/gpio-da9055.c b/drivers/gpio/gpio-da9055.c index 7ef0820032bd..f992997bc301 100644 --- a/drivers/gpio/gpio-da9055.c +++ b/drivers/gpio/gpio-da9055.c @@ -134,7 +134,7 @@ static struct gpio_chip reference_gp = { .direction_input = da9055_gpio_direction_input, .direction_output = da9055_gpio_direction_output, .to_irq = da9055_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, .ngpio = 3, .base = -1, }; diff --git a/drivers/gpio/gpio-ich.c b/drivers/gpio/gpio-ich.c index 814addb62d2c..f5bf3c38bca6 100644 --- a/drivers/gpio/gpio-ich.c +++ b/drivers/gpio/gpio-ich.c @@ -252,7 +252,7 @@ static void ichx_gpiolib_setup(struct gpio_chip *chip) chip->direction_output = ichx_gpio_direction_output; chip->base = modparam_gpiobase; chip->ngpio = ichx_priv.desc->ngpio; - chip->can_sleep = 0; + chip->can_sleep = false; chip->dbg_show = NULL; } diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index f2035c01577f..1535ebae8fc8 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -425,7 +425,7 @@ static int intel_gpio_probe(struct pci_dev *pdev, priv->chip.to_irq = intel_gpio_to_irq; priv->chip.base = gpio_base; priv->chip.ngpio = ddata->ngpio; - priv->chip.can_sleep = 0; + priv->chip.can_sleep = false; priv->pdev = pdev; spin_lock_init(&priv->lock); diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c index efdc3924d7df..c6d88173f5a2 100644 --- a/drivers/gpio/gpio-kempld.c +++ b/drivers/gpio/gpio-kempld.c @@ -167,7 +167,7 @@ static int kempld_gpio_probe(struct platform_device *pdev) chip->label = "gpio-kempld"; chip->owner = THIS_MODULE; chip->dev = dev; - chip->can_sleep = 1; + chip->can_sleep = true; if (pdata && pdata->gpio_base) chip->base = pdata->gpio_base; else diff --git a/drivers/gpio/gpio-ks8695.c b/drivers/gpio/gpio-ks8695.c index a3ac66ea364b..464a83de0d6a 100644 --- a/drivers/gpio/gpio-ks8695.c +++ b/drivers/gpio/gpio-ks8695.c @@ -228,7 +228,7 @@ static struct gpio_chip ks8695_gpio_chip = { .to_irq = ks8695_gpio_to_irq, .base = 0, .ngpio = 16, - .can_sleep = 0, + .can_sleep = false, }; /* Register the GPIOs */ diff --git a/drivers/gpio/gpio-lpc32xx.c b/drivers/gpio/gpio-lpc32xx.c index a7093e010149..225344d66404 100644 --- a/drivers/gpio/gpio-lpc32xx.c +++ b/drivers/gpio/gpio-lpc32xx.c @@ -448,7 +448,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPIO_P0_GRP, .ngpio = LPC32XX_GPIO_P0_MAX, .names = gpio_p0_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p0, }, @@ -464,7 +464,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPIO_P1_GRP, .ngpio = LPC32XX_GPIO_P1_MAX, .names = gpio_p1_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p1, }, @@ -479,7 +479,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPIO_P2_GRP, .ngpio = LPC32XX_GPIO_P2_MAX, .names = gpio_p2_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p2, }, @@ -495,7 +495,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPIO_P3_GRP, .ngpio = LPC32XX_GPIO_P3_MAX, .names = gpio_p3_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p3, }, @@ -509,7 +509,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPI_P3_GRP, .ngpio = LPC32XX_GPI_P3_MAX, .names = gpi_p3_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p3, }, @@ -523,7 +523,7 @@ static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = { .base = LPC32XX_GPO_P3_GRP, .ngpio = LPC32XX_GPO_P3_MAX, .names = gpo_p3_names, - .can_sleep = 0, + .can_sleep = false, }, .gpio_grp = &gpio_grp_regs_p3, }, diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c index 1a7443ee6016..c283cd3b247a 100644 --- a/drivers/gpio/gpio-lynxpoint.c +++ b/drivers/gpio/gpio-lynxpoint.c @@ -391,7 +391,7 @@ static int lp_gpio_probe(struct platform_device *pdev) gc->set = lp_gpio_set; gc->base = -1; gc->ngpio = LP_NUM_GPIO; - gc->can_sleep = 0; + gc->can_sleep = false; gc->dev = dev; /* set up interrupts */ diff --git a/drivers/gpio/gpio-max730x.c b/drivers/gpio/gpio-max730x.c index f4f4ed19bdc1..89226a36b08c 100644 --- a/drivers/gpio/gpio-max730x.c +++ b/drivers/gpio/gpio-max730x.c @@ -188,7 +188,7 @@ int __max730x_probe(struct max7301 *ts) ts->chip.set = max7301_set; ts->chip.ngpio = PIN_NUMBER; - ts->chip.can_sleep = 1; + ts->chip.can_sleep = true; ts->chip.dev = dev; ts->chip.owner = THIS_MODULE; diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 91ad74dea8ce..36cb290764b6 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -564,7 +564,7 @@ static int max732x_setup_gpio(struct max732x_chip *chip, gc->set = max732x_gpio_set_value; } gc->get = max732x_gpio_get_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = gpio_start; gc->ngpio = port; diff --git a/drivers/gpio/gpio-mc33880.c b/drivers/gpio/gpio-mc33880.c index c0b7835f5136..553a80a5eaf3 100644 --- a/drivers/gpio/gpio-mc33880.c +++ b/drivers/gpio/gpio-mc33880.c @@ -115,7 +115,7 @@ static int mc33880_probe(struct spi_device *spi) mc->chip.set = mc33880_set; mc->chip.base = pdata->base; mc->chip.ngpio = PIN_NUMBER; - mc->chip.can_sleep = 1; + mc->chip.can_sleep = true; mc->chip.dev = &spi->dev; mc->chip.owner = THIS_MODULE; diff --git a/drivers/gpio/gpio-mc9s08dz60.c b/drivers/gpio/gpio-mc9s08dz60.c index 0ab700046a23..dce35ff00db7 100644 --- a/drivers/gpio/gpio-mc9s08dz60.c +++ b/drivers/gpio/gpio-mc9s08dz60.c @@ -102,7 +102,7 @@ static int mc9s08dz60_probe(struct i2c_client *client, mc9s->chip.dev = &client->dev; mc9s->chip.owner = THIS_MODULE; mc9s->chip.ngpio = GPIO_NUM; - mc9s->chip.can_sleep = 1; + mc9s->chip.can_sleep = true; mc9s->chip.get = mc9s08dz60_get_value; mc9s->chip.set = mc9s08dz60_set_value; mc9s->chip.direction_output = mc9s08dz60_direction_output; diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 2deb0c5e54a4..b16401ee4766 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -425,7 +425,7 @@ static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev, } mcp->chip.base = base; - mcp->chip.can_sleep = 1; + mcp->chip.can_sleep = true; mcp->chip.dev = dev; mcp->chip.owner = THIS_MODULE; diff --git a/drivers/gpio/gpio-ml-ioh.c b/drivers/gpio/gpio-ml-ioh.c index 5c94af3c84e0..d51329d23d38 100644 --- a/drivers/gpio/gpio-ml-ioh.c +++ b/drivers/gpio/gpio-ml-ioh.c @@ -242,7 +242,7 @@ static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port) gpio->dbg_show = NULL; gpio->base = -1; gpio->ngpio = num_port; - gpio->can_sleep = 0; + gpio->can_sleep = false; gpio->to_irq = ioh_gpio_to_irq; } diff --git a/drivers/gpio/gpio-msic.c b/drivers/gpio/gpio-msic.c index 69d60ab1d698..8f70ded82a2b 100644 --- a/drivers/gpio/gpio-msic.c +++ b/drivers/gpio/gpio-msic.c @@ -292,7 +292,7 @@ static int platform_msic_gpio_probe(struct platform_device *pdev) mg->chip.to_irq = msic_gpio_to_irq; mg->chip.base = pdata->gpio_base; mg->chip.ngpio = MSIC_NUM_GPIO; - mg->chip.can_sleep = 1; + mg->chip.can_sleep = true; mg->chip.dev = dev; mutex_init(&mg->buslock); diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 3c3321f94053..a8908009803f 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -600,7 +600,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev) mvchip->chip.to_irq = mvebu_gpio_to_irq; mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK; mvchip->chip.ngpio = ngpios; - mvchip->chip.can_sleep = 0; + mvchip->chip.can_sleep = false; mvchip->chip.of_node = np; mvchip->chip.dbg_show = mvebu_gpio_dbg_show; diff --git a/drivers/gpio/gpio-octeon.c b/drivers/gpio/gpio-octeon.c index 71a4a318315d..dbb08546b9ec 100644 --- a/drivers/gpio/gpio-octeon.c +++ b/drivers/gpio/gpio-octeon.c @@ -111,7 +111,7 @@ static int octeon_gpio_probe(struct platform_device *pdev) chip->dev = &pdev->dev; chip->owner = THIS_MODULE; chip->base = 0; - chip->can_sleep = 0; + chip->can_sleep = false; chip->ngpio = 20; chip->direction_input = octeon_gpio_dir_in; chip->get = octeon_gpio_get; diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c index 11801e986dd9..da9d33252e56 100644 --- a/drivers/gpio/gpio-palmas.c +++ b/drivers/gpio/gpio-palmas.c @@ -182,7 +182,7 @@ static int palmas_gpio_probe(struct platform_device *pdev) palmas_gpio->gpio_chip.owner = THIS_MODULE; palmas_gpio->gpio_chip.label = dev_name(&pdev->dev); palmas_gpio->gpio_chip.ngpio = dev_data->ngpio; - palmas_gpio->gpio_chip.can_sleep = 1; + palmas_gpio->gpio_chip.can_sleep = true; palmas_gpio->gpio_chip.direction_input = palmas_gpio_input; palmas_gpio->gpio_chip.direction_output = palmas_gpio_output; palmas_gpio->gpio_chip.to_irq = palmas_gpio_to_irq; diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 6e48c07e3d8c..019b23b955a2 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -354,7 +354,7 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) gc->direction_output = pca953x_gpio_direction_output; gc->get = pca953x_gpio_get_value; gc->set = pca953x_gpio_set_value; - gc->can_sleep = 1; + gc->can_sleep = true; gc->base = chip->gpio_start; gc->ngpio = gpios; diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 1535686e74ea..82735822bc9d 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -305,7 +305,7 @@ static int pcf857x_probe(struct i2c_client *client, spin_lock_init(&gpio->slock); gpio->chip.base = pdata ? pdata->gpio_base : -1; - gpio->chip.can_sleep = 1; + gpio->chip.can_sleep = true; gpio->chip.dev = &client->dev; gpio->chip.owner = THIS_MODULE; gpio->chip.get = pcf857x_get; diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index ef7a756c9ded..9656c196772e 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -224,7 +224,7 @@ static void pch_gpio_setup(struct pch_gpio *chip) gpio->dbg_show = NULL; gpio->base = -1; gpio->ngpio = gpio_pins[chip->ioh]; - gpio->can_sleep = 0; + gpio->can_sleep = false; gpio->to_irq = pch_gpio_to_irq; } diff --git a/drivers/gpio/gpio-rc5t583.c b/drivers/gpio/gpio-rc5t583.c index e63d6a397e17..122b776fdc0b 100644 --- a/drivers/gpio/gpio-rc5t583.c +++ b/drivers/gpio/gpio-rc5t583.c @@ -133,7 +133,7 @@ static int rc5t583_gpio_probe(struct platform_device *pdev) rc5t583_gpio->gpio_chip.get = rc5t583_gpio_get, rc5t583_gpio->gpio_chip.to_irq = rc5t583_gpio_to_irq, rc5t583_gpio->gpio_chip.ngpio = RC5T583_MAX_GPIO, - rc5t583_gpio->gpio_chip.can_sleep = 1, + rc5t583_gpio->gpio_chip.can_sleep = true, rc5t583_gpio->gpio_chip.dev = &pdev->dev; rc5t583_gpio->gpio_chip.base = -1; rc5t583_gpio->rc5t583 = rc5t583; diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index f2fb12c18da9..68e3fcb1acea 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -146,7 +146,7 @@ static void gsta_gpio_setup(struct gsta_gpio *chip) /* called from probe */ gpio->dbg_show = NULL; gpio->base = gpio_base; gpio->ngpio = GSTA_NR_GPIO; - gpio->can_sleep = 0; + gpio->can_sleep = false; gpio->to_irq = gsta_gpio_to_irq; /* diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c index 2647e243d471..2776a09bee58 100644 --- a/drivers/gpio/gpio-stmpe.c +++ b/drivers/gpio/gpio-stmpe.c @@ -129,7 +129,7 @@ static struct gpio_chip template_chip = { .set = stmpe_gpio_set, .to_irq = stmpe_gpio_to_irq, .request = stmpe_gpio_request, - .can_sleep = 1, + .can_sleep = true, }; static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c index d2983e9ad6af..13d73fb2b5e1 100644 --- a/drivers/gpio/gpio-sx150x.c +++ b/drivers/gpio/gpio-sx150x.c @@ -436,7 +436,7 @@ static void sx150x_init_chip(struct sx150x_chip *chip, chip->gpio_chip.set = sx150x_gpio_set; chip->gpio_chip.to_irq = sx150x_gpio_to_irq; chip->gpio_chip.base = pdata->gpio_base; - chip->gpio_chip.can_sleep = 1; + chip->gpio_chip.can_sleep = true; chip->gpio_chip.ngpio = chip->dev_cfg->ngpios; if (pdata->oscio_is_gpo) ++chip->gpio_chip.ngpio; diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index 0502b9a041a5..66a54ea4f779 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -221,7 +221,7 @@ static int tb10x_gpio_probe(struct platform_device *pdev) tb10x_gpio->gc.free = tb10x_gpio_free; tb10x_gpio->gc.base = -1; tb10x_gpio->gc.ngpio = ngpio; - tb10x_gpio->gc.can_sleep = 0; + tb10x_gpio->gc.can_sleep = false; ret = gpiochip_add(&tb10x_gpio->gc); diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index ddb5fefaa715..1019320984d7 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -127,7 +127,7 @@ static struct gpio_chip template_chip = { .direction_output = tc3589x_gpio_direction_output, .set = tc3589x_gpio_set, .to_irq = tc3589x_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, }; static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index 521971e6a9f5..f9a8fbde108e 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -275,7 +275,7 @@ static int timbgpio_probe(struct platform_device *pdev) gc->dbg_show = NULL; gc->base = pdata->gpio_base; gc->ngpio = pdata->nr_pins; - gc->can_sleep = 0; + gc->can_sleep = false; err = gpiochip_add(gc); if (err) diff --git a/drivers/gpio/gpio-tnetv107x.c b/drivers/gpio/gpio-tnetv107x.c index 58445bb69106..4aa481579a05 100644 --- a/drivers/gpio/gpio-tnetv107x.c +++ b/drivers/gpio/gpio-tnetv107x.c @@ -176,7 +176,7 @@ static int __init tnetv107x_gpio_setup(void) ctlr = &chips[i]; ctlr->chip.label = "tnetv107x"; - ctlr->chip.can_sleep = 0; + ctlr->chip.can_sleep = false; ctlr->chip.base = base; ctlr->chip.ngpio = ngpio - base; if (ctlr->chip.ngpio > 32) diff --git a/drivers/gpio/gpio-tps6586x.c b/drivers/gpio/gpio-tps6586x.c index 29e8e750bd49..8994dfa13491 100644 --- a/drivers/gpio/gpio-tps6586x.c +++ b/drivers/gpio/gpio-tps6586x.c @@ -108,7 +108,7 @@ static int tps6586x_gpio_probe(struct platform_device *pdev) tps6586x_gpio->gpio_chip.label = pdev->name; tps6586x_gpio->gpio_chip.dev = &pdev->dev; tps6586x_gpio->gpio_chip.ngpio = 4; - tps6586x_gpio->gpio_chip.can_sleep = 1; + tps6586x_gpio->gpio_chip.can_sleep = true; /* FIXME: add handling of GPIOs as dedicated inputs */ tps6586x_gpio->gpio_chip.direction_output = tps6586x_gpio_output; diff --git a/drivers/gpio/gpio-tps65910.c b/drivers/gpio/gpio-tps65910.c index 06146219d9d2..b6e818e68007 100644 --- a/drivers/gpio/gpio-tps65910.c +++ b/drivers/gpio/gpio-tps65910.c @@ -143,7 +143,7 @@ static int tps65910_gpio_probe(struct platform_device *pdev) default: return -EINVAL; } - tps65910_gpio->gpio_chip.can_sleep = 1; + tps65910_gpio->gpio_chip.can_sleep = true; tps65910_gpio->gpio_chip.direction_input = tps65910_gpio_input; tps65910_gpio->gpio_chip.direction_output = tps65910_gpio_output; tps65910_gpio->gpio_chip.set = tps65910_gpio_set; diff --git a/drivers/gpio/gpio-tps65912.c b/drivers/gpio/gpio-tps65912.c index 276a4229b032..59ee486cb8b9 100644 --- a/drivers/gpio/gpio-tps65912.c +++ b/drivers/gpio/gpio-tps65912.c @@ -79,7 +79,7 @@ static struct gpio_chip template_chip = { .direction_output = tps65912_gpio_output, .get = tps65912_gpio_get, .set = tps65912_gpio_set, - .can_sleep = 1, + .can_sleep = true, .ngpio = 5, .base = -1, }; diff --git a/drivers/gpio/gpio-twl4030.c b/drivers/gpio/gpio-twl4030.c index 0c7e891c8651..cd06678a29f7 100644 --- a/drivers/gpio/gpio-twl4030.c +++ b/drivers/gpio/gpio-twl4030.c @@ -386,7 +386,7 @@ static struct gpio_chip template_chip = { .direction_output = twl_direction_out, .set = twl_set, .to_irq = twl_to_irq, - .can_sleep = 1, + .can_sleep = true, }; /*----------------------------------------------------------------------*/ diff --git a/drivers/gpio/gpio-twl6040.c b/drivers/gpio/gpio-twl6040.c index d420d30b86e7..0caf5cd1b47d 100644 --- a/drivers/gpio/gpio-twl6040.c +++ b/drivers/gpio/gpio-twl6040.c @@ -77,7 +77,7 @@ static struct gpio_chip twl6040gpo_chip = { .get = twl6040gpo_get, .direction_output = twl6040gpo_direction_out, .set = twl6040gpo_set, - .can_sleep = 1, + .can_sleep = true, }; /*----------------------------------------------------------------------*/ diff --git a/drivers/gpio/gpio-ucb1400.c b/drivers/gpio/gpio-ucb1400.c index 1a605f2a0f55..c6a53971387b 100644 --- a/drivers/gpio/gpio-ucb1400.c +++ b/drivers/gpio/gpio-ucb1400.c @@ -64,7 +64,7 @@ static int ucb1400_gpio_probe(struct platform_device *dev) ucb->gc.direction_output = ucb1400_gpio_dir_out; ucb->gc.get = ucb1400_gpio_get; ucb->gc.set = ucb1400_gpio_set; - ucb->gc.can_sleep = 1; + ucb->gc.can_sleep = true; err = gpiochip_add(&ucb->gc); if (err) diff --git a/drivers/gpio/gpio-viperboard.c b/drivers/gpio/gpio-viperboard.c index 5ac2919197fe..79e3b5836712 100644 --- a/drivers/gpio/gpio-viperboard.c +++ b/drivers/gpio/gpio-viperboard.c @@ -413,7 +413,7 @@ static int vprbrd_gpio_probe(struct platform_device *pdev) vb_gpio->gpioa.owner = THIS_MODULE; vb_gpio->gpioa.base = -1; vb_gpio->gpioa.ngpio = 16; - vb_gpio->gpioa.can_sleep = 1; + vb_gpio->gpioa.can_sleep = true; vb_gpio->gpioa.set = vprbrd_gpioa_set; vb_gpio->gpioa.get = vprbrd_gpioa_get; vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input; @@ -430,7 +430,7 @@ static int vprbrd_gpio_probe(struct platform_device *pdev) vb_gpio->gpiob.owner = THIS_MODULE; vb_gpio->gpiob.base = -1; vb_gpio->gpiob.ngpio = 16; - vb_gpio->gpiob.can_sleep = 1; + vb_gpio->gpiob.can_sleep = true; vb_gpio->gpiob.set = vprbrd_gpiob_set; vb_gpio->gpiob.get = vprbrd_gpiob_get; vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input; diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c index cddfa22edb41..0fd23b6a753d 100644 --- a/drivers/gpio/gpio-vx855.c +++ b/drivers/gpio/gpio-vx855.c @@ -214,7 +214,7 @@ static void vx855gpio_gpio_setup(struct vx855_gpio *vg) c->dbg_show = NULL; c->base = 0; c->ngpio = NR_VX855_GP; - c->can_sleep = 0; + c->can_sleep = false; c->names = vx855gpio_names; } diff --git a/drivers/gpio/gpio-wm831x.c b/drivers/gpio/gpio-wm831x.c index 456000c5c457..b18a1a26425e 100644 --- a/drivers/gpio/gpio-wm831x.c +++ b/drivers/gpio/gpio-wm831x.c @@ -240,7 +240,7 @@ static struct gpio_chip template_chip = { .to_irq = wm831x_gpio_to_irq, .set_debounce = wm831x_gpio_set_debounce, .dbg_show = wm831x_gpio_dbg_show, - .can_sleep = 1, + .can_sleep = true, }; static int wm831x_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-wm8350.c b/drivers/gpio/gpio-wm8350.c index fc49154be7b1..2487f9d575d3 100644 --- a/drivers/gpio/gpio-wm8350.c +++ b/drivers/gpio/gpio-wm8350.c @@ -106,7 +106,7 @@ static struct gpio_chip template_chip = { .direction_output = wm8350_gpio_direction_out, .set = wm8350_gpio_set, .to_irq = wm8350_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, }; static int wm8350_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-wm8994.c b/drivers/gpio/gpio-wm8994.c index a53dbdefc7ee..d93b6b581677 100644 --- a/drivers/gpio/gpio-wm8994.c +++ b/drivers/gpio/gpio-wm8994.c @@ -242,7 +242,7 @@ static struct gpio_chip template_chip = { .set = wm8994_gpio_set, .to_irq = wm8994_gpio_to_irq, .dbg_show = wm8994_gpio_dbg_show, - .can_sleep = 1, + .can_sleep = true, }; static int wm8994_gpio_probe(struct platform_device *pdev) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index c6326e44e2c0..94467ddb3711 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1051,7 +1051,7 @@ static void gpiochip_unexport(struct gpio_chip *chip) if (dev) { put_device(dev); device_unregister(dev); - chip->exported = 0; + chip->exported = false; status = 0; } else status = -ENODEV; diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c index 01bffc1d52fd..b80f1e150f53 100644 --- a/drivers/pinctrl/pinctrl-as3722.c +++ b/drivers/pinctrl/pinctrl-as3722.c @@ -531,7 +531,7 @@ static const struct gpio_chip as3722_gpio_chip = { .direction_input = as3722_gpio_direction_input, .direction_output = as3722_gpio_direction_output, .to_irq = as3722_gpio_to_irq, - .can_sleep = 1, + .can_sleep = true, .ngpio = AS3722_PIN_NUM, .base = -1, }; diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index a7549c4c83b4..943805185f3f 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1527,7 +1527,7 @@ static struct gpio_chip at91_gpio_template = { .set = at91_gpio_set, .to_irq = at91_gpio_to_irq, .dbg_show = at91_gpio_dbg_show, - .can_sleep = 0, + .can_sleep = false, .ngpio = MAX_NB_GPIO_PER_BANK, }; diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/pinctrl-baytrail.c index 2832576d8b12..31c8b3257a94 100644 --- a/drivers/pinctrl/pinctrl-baytrail.c +++ b/drivers/pinctrl/pinctrl-baytrail.c @@ -461,7 +461,7 @@ static int byt_gpio_probe(struct platform_device *pdev) gc->set = byt_gpio_set; gc->dbg_show = byt_gpio_dbg_show; gc->base = -1; - gc->can_sleep = 0; + gc->can_sleep = false; gc->dev = dev; ret = gpiochip_add(gc); diff --git a/drivers/pinctrl/pinctrl-bcm2835.c b/drivers/pinctrl/pinctrl-bcm2835.c index c05c1ef2cc3c..3d907de9bc91 100644 --- a/drivers/pinctrl/pinctrl-bcm2835.c +++ b/drivers/pinctrl/pinctrl-bcm2835.c @@ -384,7 +384,7 @@ static struct gpio_chip bcm2835_gpio_chip = { .to_irq = bcm2835_gpio_to_irq, .base = -1, .ngpio = BCM2835_NUM_GPIOS, - .can_sleep = 0, + .can_sleep = false, }; static irqreturn_t bcm2835_gpio_irq_handler(int irq, void *dev_id) diff --git a/drivers/pinctrl/pinctrl-nomadik.c b/drivers/pinctrl/pinctrl-nomadik.c index 7111c3b59130..a21820fc4b7c 100644 --- a/drivers/pinctrl/pinctrl-nomadik.c +++ b/drivers/pinctrl/pinctrl-nomadik.c @@ -904,7 +904,7 @@ static struct gpio_chip nmk_gpio_template = { .set = nmk_gpio_set_output, .to_irq = nmk_gpio_to_irq, .dbg_show = nmk_gpio_dbg_show, - .can_sleep = 0, + .can_sleep = false, }; void nmk_gpio_clocks_enable(void) diff --git a/drivers/pinctrl/pinctrl-sunxi.c b/drivers/pinctrl/pinctrl-sunxi.c index 119d2ddedfe7..6b181cb90d39 100644 --- a/drivers/pinctrl/pinctrl-sunxi.c +++ b/drivers/pinctrl/pinctrl-sunxi.c @@ -547,7 +547,7 @@ static struct gpio_chip sunxi_pinctrl_gpio_chip = { .of_xlate = sunxi_pinctrl_gpio_of_xlate, .to_irq = sunxi_pinctrl_gpio_to_irq, .of_gpio_n_cells = 3, - .can_sleep = 0, + .can_sleep = false, }; static int sunxi_pinctrl_irq_set_type(struct irq_data *d, diff --git a/drivers/pinctrl/vt8500/pinctrl-wmt.c b/drivers/pinctrl/vt8500/pinctrl-wmt.c index 39aec0850810..b28d1af9c232 100644 --- a/drivers/pinctrl/vt8500/pinctrl-wmt.c +++ b/drivers/pinctrl/vt8500/pinctrl-wmt.c @@ -565,7 +565,7 @@ static struct gpio_chip wmt_gpio_chip = { .direction_output = wmt_gpio_direction_output, .get = wmt_gpio_get_value, .set = wmt_gpio_set_value, - .can_sleep = 0, + .can_sleep = false, }; int wmt_pinctrl_probe(struct platform_device *pdev, diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 656a27efb2c8..804ec45365b7 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -36,14 +36,15 @@ struct seq_file; * @ngpio: the number of GPIOs handled by this controller; the last GPIO * handled is (base + ngpio - 1). * @desc: array of ngpio descriptors. Private. - * @can_sleep: flag must be set iff get()/set() methods sleep, as they - * must while accessing GPIO expander chips over I2C or SPI * @names: if set, must be an array of strings to use as alternative * names for the GPIOs in this chip. Any entry in the array * may be NULL if there is no alias for the GPIO, however the * array must be @ngpio entries long. A name can include a single printk * format specifier for an unsigned int. It is substituted by the actual * number of the gpio. + * @can_sleep: flag must be set iff get()/set() methods sleep, as they + * must while accessing GPIO expander chips over I2C or SPI + * @exported: flags if the gpiochip is exported for use from sysfs. Private. * * A gpio_chip can help platforms abstract various sources of GPIOs so * they can all be accessed through a common programing interface. @@ -88,8 +89,8 @@ struct gpio_chip { u16 ngpio; struct gpio_desc *desc; const char *const *names; - unsigned can_sleep:1; - unsigned exported:1; + bool can_sleep; + bool exported; #if defined(CONFIG_OF_GPIO) /* -- cgit v1.2.3-59-g8ed1b From ac2df527fb407b61f9c812a99035b62a75a77d6d Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Sat, 24 Aug 2013 20:10:41 +0200 Subject: clk: Add common __clk_get(), __clk_put() implementations This patch adds common __clk_get(), __clk_put() clkdev helpers that replace their platform specific counterparts when the common clock API is used. The owner module pointer field is added to struct clk so a reference to the clock supplier module can be taken by the clock consumers. The owner module is assigned while the clock is being registered, in functions _clk_register() and __clk_register(). Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park Acked-by: Russell King --- arch/arm/include/asm/clkdev.h | 2 ++ arch/blackfin/include/asm/clkdev.h | 2 ++ arch/mips/include/asm/clkdev.h | 2 ++ arch/sh/include/asm/clkdev.h | 2 ++ drivers/clk/clk.c | 26 ++++++++++++++++++++++++++ include/linux/clk-private.h | 3 +++ include/linux/clkdev.h | 5 +++++ 7 files changed, 42 insertions(+) (limited to 'include/linux') diff --git a/arch/arm/include/asm/clkdev.h b/arch/arm/include/asm/clkdev.h index 80751c15c300..4e8a4b27d7c7 100644 --- a/arch/arm/include/asm/clkdev.h +++ b/arch/arm/include/asm/clkdev.h @@ -14,12 +14,14 @@ #include +#ifndef CONFIG_COMMON_CLK #ifdef CONFIG_HAVE_MACH_CLKDEV #include #else #define __clk_get(clk) ({ 1; }) #define __clk_put(clk) do { } while (0) #endif +#endif static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) { diff --git a/arch/blackfin/include/asm/clkdev.h b/arch/blackfin/include/asm/clkdev.h index 9053beda8c50..7ac2436856a5 100644 --- a/arch/blackfin/include/asm/clkdev.h +++ b/arch/blackfin/include/asm/clkdev.h @@ -8,7 +8,9 @@ static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) return kzalloc(size, GFP_KERNEL); } +#ifndef CONFIG_COMMON_CLK #define __clk_put(clk) #define __clk_get(clk) ({ 1; }) +#endif #endif diff --git a/arch/mips/include/asm/clkdev.h b/arch/mips/include/asm/clkdev.h index 262475414e5f..1b3ad7b09dc1 100644 --- a/arch/mips/include/asm/clkdev.h +++ b/arch/mips/include/asm/clkdev.h @@ -14,8 +14,10 @@ #include +#ifndef CONFIG_COMMON_CLK #define __clk_get(clk) ({ 1; }) #define __clk_put(clk) do { } while (0) +#endif static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) { diff --git a/arch/sh/include/asm/clkdev.h b/arch/sh/include/asm/clkdev.h index 6ba91868201c..c41901465fb0 100644 --- a/arch/sh/include/asm/clkdev.h +++ b/arch/sh/include/asm/clkdev.h @@ -25,7 +25,9 @@ static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size) return kzalloc(size, GFP_KERNEL); } +#ifndef CONFIG_COMMON_CLK #define __clk_put(clk) #define __clk_get(clk) ({ 1; }) +#endif #endif /* __CLKDEV_H__ */ diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index c687dc8d0b64..baa2f66a7d19 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1813,6 +1813,10 @@ struct clk *__clk_register(struct device *dev, struct clk_hw *hw) clk->flags = hw->init->flags; clk->parent_names = hw->init->parent_names; clk->num_parents = hw->init->num_parents; + if (dev && dev->driver) + clk->owner = dev->driver->owner; + else + clk->owner = NULL; ret = __clk_init(dev, clk); if (ret) @@ -1833,6 +1837,8 @@ static int _clk_register(struct device *dev, struct clk_hw *hw, struct clk *clk) goto fail_name; } clk->ops = hw->init->ops; + if (dev && dev->driver) + clk->owner = dev->driver->owner; clk->hw = hw; clk->flags = hw->init->flags; clk->num_parents = hw->init->num_parents; @@ -1973,6 +1979,26 @@ void devm_clk_unregister(struct device *dev, struct clk *clk) } EXPORT_SYMBOL_GPL(devm_clk_unregister); +/* + * clkdev helpers + */ +int __clk_get(struct clk *clk) +{ + if (clk && !try_module_get(clk->owner)) + return 0; + + return 1; +} + +void __clk_put(struct clk *clk) +{ + if (WARN_ON_ONCE(IS_ERR(clk))) + return; + + if (clk) + module_put(clk->owner); +} + /*** clk rate change notifiers ***/ /** diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 8138c94409f3..8cb1865e7d9d 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -25,10 +25,13 @@ #ifdef CONFIG_COMMON_CLK +struct module; + struct clk { const char *name; const struct clk_ops *ops; struct clk_hw *hw; + struct module *owner; struct clk *parent; const char **parent_names; struct clk **parents; diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h index a6a6f603103b..94bad77eeb4a 100644 --- a/include/linux/clkdev.h +++ b/include/linux/clkdev.h @@ -43,4 +43,9 @@ int clk_add_alias(const char *, const char *, char *, struct device *); int clk_register_clkdev(struct clk *, const char *, const char *, ...); int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t); +#ifdef CONFIG_COMMON_CLK +int __clk_get(struct clk *clk); +void __clk_put(struct clk *clk); +#endif + #endif -- cgit v1.2.3-59-g8ed1b From fcb0ee6a3d331fb23dbb546500021f6e4cac5689 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Sat, 24 Aug 2013 15:00:10 +0200 Subject: clk: Implement clk_unregister clk_unregister() is currently not implemented and it is required when a clock provider module needs to be unloaded. Normally the clock supplier module is prevented to be unloaded by taking reference on the module in clk_get(). For cases when the clock supplier module deinitializes despite the consumers of its clocks holding a reference on the module, e.g. when the driver is unbound through "unbind" sysfs attribute, there are empty clock ops added. These ops are assigned temporarily to struct clk and used until all consumers release the clock, to avoid invoking callbacks from the module which just got removed. Signed-off-by: Jiada Wang Signed-off-by: Sylwester Nawrocki Signed-off-by: Kyungmin Park --- drivers/clk/clk.c | 121 ++++++++++++++++++++++++++++++++++++++++++-- include/linux/clk-private.h | 2 + 2 files changed, 120 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index baa2f66a7d19..da7b33e4c5a2 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -345,6 +345,21 @@ out: return ret; } + /** + * clk_debug_unregister - remove a clk node from the debugfs clk tree + * @clk: the clk being removed from the debugfs clk tree + * + * Dynamically removes a clk and all it's children clk nodes from the + * debugfs clk tree if clk->dentry points to debugfs created by + * clk_debug_register in __clk_init. + * + * Caller must hold prepare_lock. + */ +static void clk_debug_unregister(struct clk *clk) +{ + debugfs_remove_recursive(clk->dentry); +} + /** * clk_debug_reparent - reparent clk node in the debugfs clk tree * @clk: the clk being reparented @@ -435,6 +450,9 @@ static inline int clk_debug_register(struct clk *clk) { return 0; } static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent) { } +static inline void clk_debug_unregister(struct clk *clk) +{ +} #endif /* caller must hold prepare_lock */ @@ -1778,6 +1796,7 @@ int __clk_init(struct device *dev, struct clk *clk) clk_debug_register(clk); + kref_init(&clk->ref); out: clk_prepare_unlock(); @@ -1913,13 +1932,104 @@ fail_out: } EXPORT_SYMBOL_GPL(clk_register); +/* + * Free memory allocated for a clock. + * Caller must hold prepare_lock. + */ +static void __clk_release(struct kref *ref) +{ + struct clk *clk = container_of(ref, struct clk, ref); + int i = clk->num_parents; + + kfree(clk->parents); + while (--i >= 0) + kfree(clk->parent_names[i]); + + kfree(clk->parent_names); + kfree(clk->name); + kfree(clk); +} + +/* + * Empty clk_ops for unregistered clocks. These are used temporarily + * after clk_unregister() was called on a clock and until last clock + * consumer calls clk_put() and the struct clk object is freed. + */ +static int clk_nodrv_prepare_enable(struct clk_hw *hw) +{ + return -ENXIO; +} + +static void clk_nodrv_disable_unprepare(struct clk_hw *hw) +{ + WARN_ON_ONCE(1); +} + +static int clk_nodrv_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + return -ENXIO; +} + +static int clk_nodrv_set_parent(struct clk_hw *hw, u8 index) +{ + return -ENXIO; +} + +static const struct clk_ops clk_nodrv_ops = { + .enable = clk_nodrv_prepare_enable, + .disable = clk_nodrv_disable_unprepare, + .prepare = clk_nodrv_prepare_enable, + .unprepare = clk_nodrv_disable_unprepare, + .set_rate = clk_nodrv_set_rate, + .set_parent = clk_nodrv_set_parent, +}; + /** * clk_unregister - unregister a currently registered clock * @clk: clock to unregister - * - * Currently unimplemented. */ -void clk_unregister(struct clk *clk) {} +void clk_unregister(struct clk *clk) +{ + unsigned long flags; + + if (!clk || WARN_ON_ONCE(IS_ERR(clk))) + return; + + clk_prepare_lock(); + + if (clk->ops == &clk_nodrv_ops) { + pr_err("%s: unregistered clock: %s\n", __func__, clk->name); + goto out; + } + /* + * Assign empty clock ops for consumers that might still hold + * a reference to this clock. + */ + flags = clk_enable_lock(); + clk->ops = &clk_nodrv_ops; + clk_enable_unlock(flags); + + if (!hlist_empty(&clk->children)) { + struct clk *child; + + /* Reparent all children to the orphan list. */ + hlist_for_each_entry(child, &clk->children, child_node) + clk_set_parent(child, NULL); + } + + clk_debug_unregister(clk); + + hlist_del_init(&clk->child_node); + + if (clk->prepare_count) + pr_warn("%s: unregistering prepared clock: %s\n", + __func__, clk->name); + + kref_put(&clk->ref, __clk_release); +out: + clk_prepare_unlock(); +} EXPORT_SYMBOL_GPL(clk_unregister); static void devm_clk_release(struct device *dev, void *res) @@ -1987,6 +2097,7 @@ int __clk_get(struct clk *clk) if (clk && !try_module_get(clk->owner)) return 0; + kref_get(&clk->ref); return 1; } @@ -1995,6 +2106,10 @@ void __clk_put(struct clk *clk) if (WARN_ON_ONCE(IS_ERR(clk))) return; + clk_prepare_lock(); + kref_put(&clk->ref, __clk_release); + clk_prepare_unlock(); + if (clk) module_put(clk->owner); } diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 8cb1865e7d9d..72c65e05450b 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -12,6 +12,7 @@ #define __LINUX_CLK_PRIVATE_H #include +#include #include /* @@ -50,6 +51,7 @@ struct clk { #ifdef CONFIG_COMMON_CLK_DEBUG struct dentry *dentry; #endif + struct kref ref; }; /* -- cgit v1.2.3-59-g8ed1b From 63b945091a070d8d4275dc0f7699ba22cd5f9435 Mon Sep 17 00:00:00 2001 From: Tom Lendacky Date: Tue, 12 Nov 2013 11:46:16 -0600 Subject: crypto: ccp - CCP device driver and interface support These routines provide the device driver support for the AMD Cryptographic Coprocessor (CCP). Signed-off-by: Tom Lendacky Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-dev.c | 582 ++++++++++++ drivers/crypto/ccp/ccp-dev.h | 272 ++++++ drivers/crypto/ccp/ccp-ops.c | 2020 ++++++++++++++++++++++++++++++++++++++++++ drivers/crypto/ccp/ccp-pci.c | 360 ++++++++ include/linux/ccp.h | 525 +++++++++++ 5 files changed, 3759 insertions(+) create mode 100644 drivers/crypto/ccp/ccp-dev.c create mode 100644 drivers/crypto/ccp/ccp-dev.h create mode 100644 drivers/crypto/ccp/ccp-ops.c create mode 100644 drivers/crypto/ccp/ccp-pci.c create mode 100644 include/linux/ccp.h (limited to 'include/linux') diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c new file mode 100644 index 000000000000..de59df970176 --- /dev/null +++ b/drivers/crypto/ccp/ccp-dev.c @@ -0,0 +1,582 @@ +/* + * AMD Cryptographic Coprocessor (CCP) driver + * + * Copyright (C) 2013 Advanced Micro Devices, Inc. + * + * Author: Tom Lendacky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ccp-dev.h" + +MODULE_AUTHOR("Tom Lendacky "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0.0"); +MODULE_DESCRIPTION("AMD Cryptographic Coprocessor driver"); + + +static struct ccp_device *ccp_dev; +static inline struct ccp_device *ccp_get_device(void) +{ + return ccp_dev; +} + +static inline void ccp_add_device(struct ccp_device *ccp) +{ + ccp_dev = ccp; +} + +static inline void ccp_del_device(struct ccp_device *ccp) +{ + ccp_dev = NULL; +} + +/** + * ccp_enqueue_cmd - queue an operation for processing by the CCP + * + * @cmd: ccp_cmd struct to be processed + * + * Queue a cmd to be processed by the CCP. If queueing the cmd + * would exceed the defined length of the cmd queue the cmd will + * only be queued if the CCP_CMD_MAY_BACKLOG flag is set and will + * result in a return code of -EBUSY. + * + * The callback routine specified in the ccp_cmd struct will be + * called to notify the caller of completion (if the cmd was not + * backlogged) or advancement out of the backlog. If the cmd has + * advanced out of the backlog the "err" value of the callback + * will be -EINPROGRESS. Any other "err" value during callback is + * the result of the operation. + * + * The cmd has been successfully queued if: + * the return code is -EINPROGRESS or + * the return code is -EBUSY and CCP_CMD_MAY_BACKLOG flag is set + */ +int ccp_enqueue_cmd(struct ccp_cmd *cmd) +{ + struct ccp_device *ccp = ccp_get_device(); + unsigned long flags; + unsigned int i; + int ret; + + if (!ccp) + return -ENODEV; + + /* Caller must supply a callback routine */ + if (!cmd->callback) + return -EINVAL; + + cmd->ccp = ccp; + + spin_lock_irqsave(&ccp->cmd_lock, flags); + + i = ccp->cmd_q_count; + + if (ccp->cmd_count >= MAX_CMD_QLEN) { + ret = -EBUSY; + if (cmd->flags & CCP_CMD_MAY_BACKLOG) + list_add_tail(&cmd->entry, &ccp->backlog); + } else { + ret = -EINPROGRESS; + ccp->cmd_count++; + list_add_tail(&cmd->entry, &ccp->cmd); + + /* Find an idle queue */ + if (!ccp->suspending) { + for (i = 0; i < ccp->cmd_q_count; i++) { + if (ccp->cmd_q[i].active) + continue; + + break; + } + } + } + + spin_unlock_irqrestore(&ccp->cmd_lock, flags); + + /* If we found an idle queue, wake it up */ + if (i < ccp->cmd_q_count) + wake_up_process(ccp->cmd_q[i].kthread); + + return ret; +} +EXPORT_SYMBOL_GPL(ccp_enqueue_cmd); + +static void ccp_do_cmd_backlog(struct work_struct *work) +{ + struct ccp_cmd *cmd = container_of(work, struct ccp_cmd, work); + struct ccp_device *ccp = cmd->ccp; + unsigned long flags; + unsigned int i; + + cmd->callback(cmd->data, -EINPROGRESS); + + spin_lock_irqsave(&ccp->cmd_lock, flags); + + ccp->cmd_count++; + list_add_tail(&cmd->entry, &ccp->cmd); + + /* Find an idle queue */ + for (i = 0; i < ccp->cmd_q_count; i++) { + if (ccp->cmd_q[i].active) + continue; + + break; + } + + spin_unlock_irqrestore(&ccp->cmd_lock, flags); + + /* If we found an idle queue, wake it up */ + if (i < ccp->cmd_q_count) + wake_up_process(ccp->cmd_q[i].kthread); +} + +static struct ccp_cmd *ccp_dequeue_cmd(struct ccp_cmd_queue *cmd_q) +{ + struct ccp_device *ccp = cmd_q->ccp; + struct ccp_cmd *cmd = NULL; + struct ccp_cmd *backlog = NULL; + unsigned long flags; + + spin_lock_irqsave(&ccp->cmd_lock, flags); + + cmd_q->active = 0; + + if (ccp->suspending) { + cmd_q->suspended = 1; + + spin_unlock_irqrestore(&ccp->cmd_lock, flags); + wake_up_interruptible(&ccp->suspend_queue); + + return NULL; + } + + if (ccp->cmd_count) { + cmd_q->active = 1; + + cmd = list_first_entry(&ccp->cmd, struct ccp_cmd, entry); + list_del(&cmd->entry); + + ccp->cmd_count--; + } + + if (!list_empty(&ccp->backlog)) { + backlog = list_first_entry(&ccp->backlog, struct ccp_cmd, + entry); + list_del(&backlog->entry); + } + + spin_unlock_irqrestore(&ccp->cmd_lock, flags); + + if (backlog) { + INIT_WORK(&backlog->work, ccp_do_cmd_backlog); + schedule_work(&backlog->work); + } + + return cmd; +} + +static void ccp_do_cmd_complete(struct work_struct *work) +{ + struct ccp_cmd *cmd = container_of(work, struct ccp_cmd, work); + + cmd->callback(cmd->data, cmd->ret); +} + +static int ccp_cmd_queue_thread(void *data) +{ + struct ccp_cmd_queue *cmd_q = (struct ccp_cmd_queue *)data; + struct ccp_cmd *cmd; + + set_current_state(TASK_INTERRUPTIBLE); + while (!kthread_should_stop()) { + schedule(); + + set_current_state(TASK_INTERRUPTIBLE); + + cmd = ccp_dequeue_cmd(cmd_q); + if (!cmd) + continue; + + __set_current_state(TASK_RUNNING); + + /* Execute the command */ + cmd->ret = ccp_run_cmd(cmd_q, cmd); + + /* Schedule the completion callback */ + INIT_WORK(&cmd->work, ccp_do_cmd_complete); + schedule_work(&cmd->work); + } + + __set_current_state(TASK_RUNNING); + + return 0; +} + +static int ccp_trng_read(struct hwrng *rng, void *data, size_t max, bool wait) +{ + struct ccp_device *ccp = container_of(rng, struct ccp_device, hwrng); + u32 trng_value; + int len = min_t(int, sizeof(trng_value), max); + + /* + * Locking is provided by the caller so we can update device + * hwrng-related fields safely + */ + trng_value = ioread32(ccp->io_regs + TRNG_OUT_REG); + if (!trng_value) { + /* Zero is returned if not data is available or if a + * bad-entropy error is present. Assume an error if + * we exceed TRNG_RETRIES reads of zero. + */ + if (ccp->hwrng_retries++ > TRNG_RETRIES) + return -EIO; + + return 0; + } + + /* Reset the counter and save the rng value */ + ccp->hwrng_retries = 0; + memcpy(data, &trng_value, len); + + return len; +} + +/** + * ccp_alloc_struct - allocate and initialize the ccp_device struct + * + * @dev: device struct of the CCP + */ +struct ccp_device *ccp_alloc_struct(struct device *dev) +{ + struct ccp_device *ccp; + + ccp = kzalloc(sizeof(*ccp), GFP_KERNEL); + if (ccp == NULL) { + dev_err(dev, "unable to allocate device struct\n"); + return NULL; + } + ccp->dev = dev; + + INIT_LIST_HEAD(&ccp->cmd); + INIT_LIST_HEAD(&ccp->backlog); + + spin_lock_init(&ccp->cmd_lock); + mutex_init(&ccp->req_mutex); + mutex_init(&ccp->ksb_mutex); + ccp->ksb_count = KSB_COUNT; + ccp->ksb_start = 0; + + return ccp; +} + +/** + * ccp_init - initialize the CCP device + * + * @ccp: ccp_device struct + */ +int ccp_init(struct ccp_device *ccp) +{ + struct device *dev = ccp->dev; + struct ccp_cmd_queue *cmd_q; + struct dma_pool *dma_pool; + char dma_pool_name[MAX_DMAPOOL_NAME_LEN]; + unsigned int qmr, qim, i; + int ret; + + /* Find available queues */ + qim = 0; + qmr = ioread32(ccp->io_regs + Q_MASK_REG); + for (i = 0; i < MAX_HW_QUEUES; i++) { + if (!(qmr & (1 << i))) + continue; + + /* Allocate a dma pool for this queue */ + snprintf(dma_pool_name, sizeof(dma_pool_name), "ccp_q%d", i); + dma_pool = dma_pool_create(dma_pool_name, dev, + CCP_DMAPOOL_MAX_SIZE, + CCP_DMAPOOL_ALIGN, 0); + if (!dma_pool) { + dev_err(dev, "unable to allocate dma pool\n"); + ret = -ENOMEM; + goto e_pool; + } + + cmd_q = &ccp->cmd_q[ccp->cmd_q_count]; + ccp->cmd_q_count++; + + cmd_q->ccp = ccp; + cmd_q->id = i; + cmd_q->dma_pool = dma_pool; + + /* Reserve 2 KSB regions for the queue */ + cmd_q->ksb_key = KSB_START + ccp->ksb_start++; + cmd_q->ksb_ctx = KSB_START + ccp->ksb_start++; + ccp->ksb_count -= 2; + + /* Preset some register values and masks that are queue + * number dependent + */ + cmd_q->reg_status = ccp->io_regs + CMD_Q_STATUS_BASE + + (CMD_Q_STATUS_INCR * i); + cmd_q->reg_int_status = ccp->io_regs + CMD_Q_INT_STATUS_BASE + + (CMD_Q_STATUS_INCR * i); + cmd_q->int_ok = 1 << (i * 2); + cmd_q->int_err = 1 << ((i * 2) + 1); + + cmd_q->free_slots = CMD_Q_DEPTH(ioread32(cmd_q->reg_status)); + + init_waitqueue_head(&cmd_q->int_queue); + + /* Build queue interrupt mask (two interrupts per queue) */ + qim |= cmd_q->int_ok | cmd_q->int_err; + + dev_dbg(dev, "queue #%u available\n", i); + } + if (ccp->cmd_q_count == 0) { + dev_notice(dev, "no command queues available\n"); + ret = -EIO; + goto e_pool; + } + dev_notice(dev, "%u command queues available\n", ccp->cmd_q_count); + + /* Disable and clear interrupts until ready */ + iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG); + for (i = 0; i < ccp->cmd_q_count; i++) { + cmd_q = &ccp->cmd_q[i]; + + ioread32(cmd_q->reg_int_status); + ioread32(cmd_q->reg_status); + } + iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG); + + /* Request an irq */ + ret = ccp->get_irq(ccp); + if (ret) { + dev_err(dev, "unable to allocate an IRQ\n"); + goto e_pool; + } + + /* Initialize the queues used to wait for KSB space and suspend */ + init_waitqueue_head(&ccp->ksb_queue); + init_waitqueue_head(&ccp->suspend_queue); + + /* Create a kthread for each queue */ + for (i = 0; i < ccp->cmd_q_count; i++) { + struct task_struct *kthread; + + cmd_q = &ccp->cmd_q[i]; + + kthread = kthread_create(ccp_cmd_queue_thread, cmd_q, + "ccp-q%u", cmd_q->id); + if (IS_ERR(kthread)) { + dev_err(dev, "error creating queue thread (%ld)\n", + PTR_ERR(kthread)); + ret = PTR_ERR(kthread); + goto e_kthread; + } + + cmd_q->kthread = kthread; + wake_up_process(kthread); + } + + /* Register the RNG */ + ccp->hwrng.name = "ccp-rng"; + ccp->hwrng.read = ccp_trng_read; + ret = hwrng_register(&ccp->hwrng); + if (ret) { + dev_err(dev, "error registering hwrng (%d)\n", ret); + goto e_kthread; + } + + /* Make the device struct available before enabling interrupts */ + ccp_add_device(ccp); + + /* Enable interrupts */ + iowrite32(qim, ccp->io_regs + IRQ_MASK_REG); + + return 0; + +e_kthread: + for (i = 0; i < ccp->cmd_q_count; i++) + if (ccp->cmd_q[i].kthread) + kthread_stop(ccp->cmd_q[i].kthread); + + ccp->free_irq(ccp); + +e_pool: + for (i = 0; i < ccp->cmd_q_count; i++) + dma_pool_destroy(ccp->cmd_q[i].dma_pool); + + return ret; +} + +/** + * ccp_destroy - tear down the CCP device + * + * @ccp: ccp_device struct + */ +void ccp_destroy(struct ccp_device *ccp) +{ + struct ccp_cmd_queue *cmd_q; + struct ccp_cmd *cmd; + unsigned int qim, i; + + /* Remove general access to the device struct */ + ccp_del_device(ccp); + + /* Unregister the RNG */ + hwrng_unregister(&ccp->hwrng); + + /* Stop the queue kthreads */ + for (i = 0; i < ccp->cmd_q_count; i++) + if (ccp->cmd_q[i].kthread) + kthread_stop(ccp->cmd_q[i].kthread); + + /* Build queue interrupt mask (two interrupt masks per queue) */ + qim = 0; + for (i = 0; i < ccp->cmd_q_count; i++) { + cmd_q = &ccp->cmd_q[i]; + qim |= cmd_q->int_ok | cmd_q->int_err; + } + + /* Disable and clear interrupts */ + iowrite32(0x00, ccp->io_regs + IRQ_MASK_REG); + for (i = 0; i < ccp->cmd_q_count; i++) { + cmd_q = &ccp->cmd_q[i]; + + ioread32(cmd_q->reg_int_status); + ioread32(cmd_q->reg_status); + } + iowrite32(qim, ccp->io_regs + IRQ_STATUS_REG); + + ccp->free_irq(ccp); + + for (i = 0; i < ccp->cmd_q_count; i++) + dma_pool_destroy(ccp->cmd_q[i].dma_pool); + + /* Flush the cmd and backlog queue */ + while (!list_empty(&ccp->cmd)) { + /* Invoke the callback directly with an error code */ + cmd = list_first_entry(&ccp->cmd, struct ccp_cmd, entry); + list_del(&cmd->entry); + cmd->callback(cmd->data, -ENODEV); + } + while (!list_empty(&ccp->backlog)) { + /* Invoke the callback directly with an error code */ + cmd = list_first_entry(&ccp->backlog, struct ccp_cmd, entry); + list_del(&cmd->entry); + cmd->callback(cmd->data, -ENODEV); + } +} + +/** + * ccp_irq_handler - handle interrupts generated by the CCP device + * + * @irq: the irq associated with the interrupt + * @data: the data value supplied when the irq was created + */ +irqreturn_t ccp_irq_handler(int irq, void *data) +{ + struct device *dev = data; + struct ccp_device *ccp = dev_get_drvdata(dev); + struct ccp_cmd_queue *cmd_q; + u32 q_int, status; + unsigned int i; + + status = ioread32(ccp->io_regs + IRQ_STATUS_REG); + + for (i = 0; i < ccp->cmd_q_count; i++) { + cmd_q = &ccp->cmd_q[i]; + + q_int = status & (cmd_q->int_ok | cmd_q->int_err); + if (q_int) { + cmd_q->int_status = status; + cmd_q->q_status = ioread32(cmd_q->reg_status); + cmd_q->q_int_status = ioread32(cmd_q->reg_int_status); + + /* On error, only save the first error value */ + if ((q_int & cmd_q->int_err) && !cmd_q->cmd_error) + cmd_q->cmd_error = CMD_Q_ERROR(cmd_q->q_status); + + cmd_q->int_rcvd = 1; + + /* Acknowledge the interrupt and wake the kthread */ + iowrite32(q_int, ccp->io_regs + IRQ_STATUS_REG); + wake_up_interruptible(&cmd_q->int_queue); + } + } + + return IRQ_HANDLED; +} + +#ifdef CONFIG_PM +bool ccp_queues_suspended(struct ccp_device *ccp) +{ + unsigned int suspended = 0; + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&ccp->cmd_lock, flags); + + for (i = 0; i < ccp->cmd_q_count; i++) + if (ccp->cmd_q[i].suspended) + suspended++; + + spin_unlock_irqrestore(&ccp->cmd_lock, flags); + + return ccp->cmd_q_count == suspended; +} +#endif + +static const struct x86_cpu_id ccp_support[] = { + { X86_VENDOR_AMD, 22, }, +}; + +static int __init ccp_mod_init(void) +{ + struct cpuinfo_x86 *cpuinfo = &boot_cpu_data; + + if (!x86_match_cpu(ccp_support)) + return -ENODEV; + + switch (cpuinfo->x86) { + case 22: + if ((cpuinfo->x86_model < 48) || (cpuinfo->x86_model > 63)) + return -ENODEV; + return ccp_pci_init(); + break; + }; + + return -ENODEV; +} + +static void __exit ccp_mod_exit(void) +{ + struct cpuinfo_x86 *cpuinfo = &boot_cpu_data; + + switch (cpuinfo->x86) { + case 22: + ccp_pci_exit(); + break; + }; +} + +module_init(ccp_mod_init); +module_exit(ccp_mod_exit); diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h new file mode 100644 index 000000000000..7ec536e702ec --- /dev/null +++ b/drivers/crypto/ccp/ccp-dev.h @@ -0,0 +1,272 @@ +/* + * AMD Cryptographic Coprocessor (CCP) driver + * + * Copyright (C) 2013 Advanced Micro Devices, Inc. + * + * Author: Tom Lendacky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __CCP_DEV_H__ +#define __CCP_DEV_H__ + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define IO_OFFSET 0x20000 + +#define MAX_DMAPOOL_NAME_LEN 32 + +#define MAX_HW_QUEUES 5 +#define MAX_CMD_QLEN 100 + +#define TRNG_RETRIES 10 + + +/****** Register Mappings ******/ +#define Q_MASK_REG 0x000 +#define TRNG_OUT_REG 0x00c +#define IRQ_MASK_REG 0x040 +#define IRQ_STATUS_REG 0x200 + +#define DEL_CMD_Q_JOB 0x124 +#define DEL_Q_ACTIVE 0x00000200 +#define DEL_Q_ID_SHIFT 6 + +#define CMD_REQ0 0x180 +#define CMD_REQ_INCR 0x04 + +#define CMD_Q_STATUS_BASE 0x210 +#define CMD_Q_INT_STATUS_BASE 0x214 +#define CMD_Q_STATUS_INCR 0x20 + +#define CMD_Q_CACHE 0x228 +#define CMD_Q_CACHE_INC 0x20 + +#define CMD_Q_ERROR(__qs) ((__qs) & 0x0000003f); +#define CMD_Q_DEPTH(__qs) (((__qs) >> 12) & 0x0000000f); + +/****** REQ0 Related Values ******/ +#define REQ0_WAIT_FOR_WRITE 0x00000004 +#define REQ0_INT_ON_COMPLETE 0x00000002 +#define REQ0_STOP_ON_COMPLETE 0x00000001 + +#define REQ0_CMD_Q_SHIFT 9 +#define REQ0_JOBID_SHIFT 3 + +/****** REQ1 Related Values ******/ +#define REQ1_PROTECT_SHIFT 27 +#define REQ1_ENGINE_SHIFT 23 +#define REQ1_KEY_KSB_SHIFT 2 + +#define REQ1_EOM 0x00000002 +#define REQ1_INIT 0x00000001 + +/* AES Related Values */ +#define REQ1_AES_TYPE_SHIFT 21 +#define REQ1_AES_MODE_SHIFT 18 +#define REQ1_AES_ACTION_SHIFT 17 +#define REQ1_AES_CFB_SIZE_SHIFT 10 + +/* XTS-AES Related Values */ +#define REQ1_XTS_AES_SIZE_SHIFT 10 + +/* SHA Related Values */ +#define REQ1_SHA_TYPE_SHIFT 21 + +/* RSA Related Values */ +#define REQ1_RSA_MOD_SIZE_SHIFT 10 + +/* Pass-Through Related Values */ +#define REQ1_PT_BW_SHIFT 12 +#define REQ1_PT_BS_SHIFT 10 + +/* ECC Related Values */ +#define REQ1_ECC_AFFINE_CONVERT 0x00200000 +#define REQ1_ECC_FUNCTION_SHIFT 18 + +/****** REQ4 Related Values ******/ +#define REQ4_KSB_SHIFT 18 +#define REQ4_MEMTYPE_SHIFT 16 + +/****** REQ6 Related Values ******/ +#define REQ6_MEMTYPE_SHIFT 16 + + +/****** Key Storage Block ******/ +#define KSB_START 77 +#define KSB_END 127 +#define KSB_COUNT (KSB_END - KSB_START + 1) +#define CCP_KSB_BITS 256 +#define CCP_KSB_BYTES 32 + +#define CCP_JOBID_MASK 0x0000003f + +#define CCP_DMAPOOL_MAX_SIZE 64 +#define CCP_DMAPOOL_ALIGN (1 << 5) + +#define CCP_REVERSE_BUF_SIZE 64 + +#define CCP_AES_KEY_KSB_COUNT 1 +#define CCP_AES_CTX_KSB_COUNT 1 + +#define CCP_XTS_AES_KEY_KSB_COUNT 1 +#define CCP_XTS_AES_CTX_KSB_COUNT 1 + +#define CCP_SHA_KSB_COUNT 1 + +#define CCP_RSA_MAX_WIDTH 4096 + +#define CCP_PASSTHRU_BLOCKSIZE 256 +#define CCP_PASSTHRU_MASKSIZE 32 +#define CCP_PASSTHRU_KSB_COUNT 1 + +#define CCP_ECC_MODULUS_BYTES 48 /* 384-bits */ +#define CCP_ECC_MAX_OPERANDS 6 +#define CCP_ECC_MAX_OUTPUTS 3 +#define CCP_ECC_SRC_BUF_SIZE 448 +#define CCP_ECC_DST_BUF_SIZE 192 +#define CCP_ECC_OPERAND_SIZE 64 +#define CCP_ECC_OUTPUT_SIZE 64 +#define CCP_ECC_RESULT_OFFSET 60 +#define CCP_ECC_RESULT_SUCCESS 0x0001 + + +struct ccp_device; +struct ccp_cmd; + +struct ccp_cmd_queue { + struct ccp_device *ccp; + + /* Queue identifier */ + u32 id; + + /* Queue dma pool */ + struct dma_pool *dma_pool; + + /* Queue reserved KSB regions */ + u32 ksb_key; + u32 ksb_ctx; + + /* Queue processing thread */ + struct task_struct *kthread; + unsigned int active; + unsigned int suspended; + + /* Number of free command slots available */ + unsigned int free_slots; + + /* Interrupt masks */ + u32 int_ok; + u32 int_err; + + /* Register addresses for queue */ + void __iomem *reg_status; + void __iomem *reg_int_status; + + /* Status values from job */ + u32 int_status; + u32 q_status; + u32 q_int_status; + u32 cmd_error; + + /* Interrupt wait queue */ + wait_queue_head_t int_queue; + unsigned int int_rcvd; +} ____cacheline_aligned; + +struct ccp_device { + struct device *dev; + + /* + * Bus specific device information + */ + void *dev_specific; + int (*get_irq)(struct ccp_device *ccp); + void (*free_irq)(struct ccp_device *ccp); + + /* + * I/O area used for device communication. The register mapping + * starts at an offset into the mapped bar. + * The CMD_REQx registers and the Delete_Cmd_Queue_Job register + * need to be protected while a command queue thread is accessing + * them. + */ + struct mutex req_mutex ____cacheline_aligned; + void __iomem *io_map; + void __iomem *io_regs; + + /* + * Master lists that all cmds are queued on. Because there can be + * more than one CCP command queue that can process a cmd a separate + * backlog list is neeeded so that the backlog completion call + * completes before the cmd is available for execution. + */ + spinlock_t cmd_lock ____cacheline_aligned; + unsigned int cmd_count; + struct list_head cmd; + struct list_head backlog; + + /* + * The command queues. These represent the queues available on the + * CCP that are available for processing cmds + */ + struct ccp_cmd_queue cmd_q[MAX_HW_QUEUES]; + unsigned int cmd_q_count; + + /* + * Support for the CCP True RNG + */ + struct hwrng hwrng; + unsigned int hwrng_retries; + + /* + * A counter used to generate job-ids for cmds submitted to the CCP + */ + atomic_t current_id ____cacheline_aligned; + + /* + * The CCP uses key storage blocks (KSB) to maintain context for certain + * operations. To prevent multiple cmds from using the same KSB range + * a command queue reserves a KSB range for the duration of the cmd. + * Each queue, will however, reserve 2 KSB blocks for operations that + * only require single KSB entries (eg. AES context/iv and key) in order + * to avoid allocation contention. This will reserve at most 10 KSB + * entries, leaving 40 KSB entries available for dynamic allocation. + */ + struct mutex ksb_mutex ____cacheline_aligned; + DECLARE_BITMAP(ksb, KSB_COUNT); + wait_queue_head_t ksb_queue; + unsigned int ksb_avail; + unsigned int ksb_count; + u32 ksb_start; + + /* Suspend support */ + unsigned int suspending; + wait_queue_head_t suspend_queue; +}; + + +int ccp_pci_init(void); +void ccp_pci_exit(void); + +struct ccp_device *ccp_alloc_struct(struct device *dev); +int ccp_init(struct ccp_device *ccp); +void ccp_destroy(struct ccp_device *ccp); +bool ccp_queues_suspended(struct ccp_device *ccp); + +irqreturn_t ccp_irq_handler(int irq, void *data); + +int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd); + +#endif diff --git a/drivers/crypto/ccp/ccp-ops.c b/drivers/crypto/ccp/ccp-ops.c new file mode 100644 index 000000000000..4be091037549 --- /dev/null +++ b/drivers/crypto/ccp/ccp-ops.c @@ -0,0 +1,2020 @@ +/* + * AMD Cryptographic Coprocessor (CCP) driver + * + * Copyright (C) 2013 Advanced Micro Devices, Inc. + * + * Author: Tom Lendacky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ccp-dev.h" + + +enum ccp_memtype { + CCP_MEMTYPE_SYSTEM = 0, + CCP_MEMTYPE_KSB, + CCP_MEMTYPE_LOCAL, + CCP_MEMTYPE__LAST, +}; + +struct ccp_dma_info { + dma_addr_t address; + unsigned int offset; + unsigned int length; + enum dma_data_direction dir; +}; + +struct ccp_dm_workarea { + struct device *dev; + struct dma_pool *dma_pool; + unsigned int length; + + u8 *address; + struct ccp_dma_info dma; +}; + +struct ccp_sg_workarea { + struct scatterlist *sg; + unsigned int nents; + unsigned int length; + + struct scatterlist *dma_sg; + struct device *dma_dev; + unsigned int dma_count; + enum dma_data_direction dma_dir; + + u32 sg_used; + + u32 bytes_left; +}; + +struct ccp_data { + struct ccp_sg_workarea sg_wa; + struct ccp_dm_workarea dm_wa; +}; + +struct ccp_mem { + enum ccp_memtype type; + union { + struct ccp_dma_info dma; + u32 ksb; + } u; +}; + +struct ccp_aes_op { + enum ccp_aes_type type; + enum ccp_aes_mode mode; + enum ccp_aes_action action; +}; + +struct ccp_xts_aes_op { + enum ccp_aes_action action; + enum ccp_xts_aes_unit_size unit_size; +}; + +struct ccp_sha_op { + enum ccp_sha_type type; + u64 msg_bits; +}; + +struct ccp_rsa_op { + u32 mod_size; + u32 input_len; +}; + +struct ccp_passthru_op { + enum ccp_passthru_bitwise bit_mod; + enum ccp_passthru_byteswap byte_swap; +}; + +struct ccp_ecc_op { + enum ccp_ecc_function function; +}; + +struct ccp_op { + struct ccp_cmd_queue *cmd_q; + + u32 jobid; + u32 ioc; + u32 soc; + u32 ksb_key; + u32 ksb_ctx; + u32 init; + u32 eom; + + struct ccp_mem src; + struct ccp_mem dst; + + union { + struct ccp_aes_op aes; + struct ccp_xts_aes_op xts; + struct ccp_sha_op sha; + struct ccp_rsa_op rsa; + struct ccp_passthru_op passthru; + struct ccp_ecc_op ecc; + } u; +}; + +/* The CCP cannot perform zero-length sha operations so the caller + * is required to buffer data for the final operation. However, a + * sha operation for a message with a total length of zero is valid + * so known values are required to supply the result. + */ +static const u8 ccp_sha1_zero[CCP_SHA_CTXSIZE] = { + 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, + 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, + 0xaf, 0xd8, 0x07, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 ccp_sha224_zero[CCP_SHA_CTXSIZE] = { + 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, + 0x47, 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, + 0x15, 0xa2, 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, + 0xc5, 0xb3, 0xe4, 0x2f, 0x00, 0x00, 0x00, 0x00, +}; + +static const u8 ccp_sha256_zero[CCP_SHA_CTXSIZE] = { + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, + 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, + 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, +}; + +static u32 ccp_addr_lo(struct ccp_dma_info *info) +{ + return lower_32_bits(info->address + info->offset); +} + +static u32 ccp_addr_hi(struct ccp_dma_info *info) +{ + return upper_32_bits(info->address + info->offset) & 0x0000ffff; +} + +static int ccp_do_cmd(struct ccp_op *op, u32 *cr, unsigned int cr_count) +{ + struct ccp_cmd_queue *cmd_q = op->cmd_q; + struct ccp_device *ccp = cmd_q->ccp; + void __iomem *cr_addr; + u32 cr0, cmd; + unsigned int i; + int ret = 0; + + /* We could read a status register to see how many free slots + * are actually available, but reading that register resets it + * and you could lose some error information. + */ + cmd_q->free_slots--; + + cr0 = (cmd_q->id << REQ0_CMD_Q_SHIFT) + | (op->jobid << REQ0_JOBID_SHIFT) + | REQ0_WAIT_FOR_WRITE; + + if (op->soc) + cr0 |= REQ0_STOP_ON_COMPLETE + | REQ0_INT_ON_COMPLETE; + + if (op->ioc || !cmd_q->free_slots) + cr0 |= REQ0_INT_ON_COMPLETE; + + /* Start at CMD_REQ1 */ + cr_addr = ccp->io_regs + CMD_REQ0 + CMD_REQ_INCR; + + mutex_lock(&ccp->req_mutex); + + /* Write CMD_REQ1 through CMD_REQx first */ + for (i = 0; i < cr_count; i++, cr_addr += CMD_REQ_INCR) + iowrite32(*(cr + i), cr_addr); + + /* Tell the CCP to start */ + wmb(); + iowrite32(cr0, ccp->io_regs + CMD_REQ0); + + mutex_unlock(&ccp->req_mutex); + + if (cr0 & REQ0_INT_ON_COMPLETE) { + /* Wait for the job to complete */ + ret = wait_event_interruptible(cmd_q->int_queue, + cmd_q->int_rcvd); + if (ret || cmd_q->cmd_error) { + /* On error delete all related jobs from the queue */ + cmd = (cmd_q->id << DEL_Q_ID_SHIFT) + | op->jobid; + + iowrite32(cmd, ccp->io_regs + DEL_CMD_Q_JOB); + + if (!ret) + ret = -EIO; + } else if (op->soc) { + /* Delete just head job from the queue on SoC */ + cmd = DEL_Q_ACTIVE + | (cmd_q->id << DEL_Q_ID_SHIFT) + | op->jobid; + + iowrite32(cmd, ccp->io_regs + DEL_CMD_Q_JOB); + } + + cmd_q->free_slots = CMD_Q_DEPTH(cmd_q->q_status); + + cmd_q->int_rcvd = 0; + } + + return ret; +} + +static int ccp_perform_aes(struct ccp_op *op) +{ + u32 cr[6]; + + /* Fill out the register contents for REQ1 through REQ6 */ + cr[0] = (CCP_ENGINE_AES << REQ1_ENGINE_SHIFT) + | (op->u.aes.type << REQ1_AES_TYPE_SHIFT) + | (op->u.aes.mode << REQ1_AES_MODE_SHIFT) + | (op->u.aes.action << REQ1_AES_ACTION_SHIFT) + | (op->ksb_key << REQ1_KEY_KSB_SHIFT); + cr[1] = op->src.u.dma.length - 1; + cr[2] = ccp_addr_lo(&op->src.u.dma); + cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT) + | (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT) + | ccp_addr_hi(&op->src.u.dma); + cr[4] = ccp_addr_lo(&op->dst.u.dma); + cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT) + | ccp_addr_hi(&op->dst.u.dma); + + if (op->u.aes.mode == CCP_AES_MODE_CFB) + cr[0] |= ((0x7f) << REQ1_AES_CFB_SIZE_SHIFT); + + if (op->eom) + cr[0] |= REQ1_EOM; + + if (op->init) + cr[0] |= REQ1_INIT; + + return ccp_do_cmd(op, cr, ARRAY_SIZE(cr)); +} + +static int ccp_perform_xts_aes(struct ccp_op *op) +{ + u32 cr[6]; + + /* Fill out the register contents for REQ1 through REQ6 */ + cr[0] = (CCP_ENGINE_XTS_AES_128 << REQ1_ENGINE_SHIFT) + | (op->u.xts.action << REQ1_AES_ACTION_SHIFT) + | (op->u.xts.unit_size << REQ1_XTS_AES_SIZE_SHIFT) + | (op->ksb_key << REQ1_KEY_KSB_SHIFT); + cr[1] = op->src.u.dma.length - 1; + cr[2] = ccp_addr_lo(&op->src.u.dma); + cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT) + | (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT) + | ccp_addr_hi(&op->src.u.dma); + cr[4] = ccp_addr_lo(&op->dst.u.dma); + cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT) + | ccp_addr_hi(&op->dst.u.dma); + + if (op->eom) + cr[0] |= REQ1_EOM; + + if (op->init) + cr[0] |= REQ1_INIT; + + return ccp_do_cmd(op, cr, ARRAY_SIZE(cr)); +} + +static int ccp_perform_sha(struct ccp_op *op) +{ + u32 cr[6]; + + /* Fill out the register contents for REQ1 through REQ6 */ + cr[0] = (CCP_ENGINE_SHA << REQ1_ENGINE_SHIFT) + | (op->u.sha.type << REQ1_SHA_TYPE_SHIFT) + | REQ1_INIT; + cr[1] = op->src.u.dma.length - 1; + cr[2] = ccp_addr_lo(&op->src.u.dma); + cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT) + | (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT) + | ccp_addr_hi(&op->src.u.dma); + + if (op->eom) { + cr[0] |= REQ1_EOM; + cr[4] = lower_32_bits(op->u.sha.msg_bits); + cr[5] = upper_32_bits(op->u.sha.msg_bits); + } else { + cr[4] = 0; + cr[5] = 0; + } + + return ccp_do_cmd(op, cr, ARRAY_SIZE(cr)); +} + +static int ccp_perform_rsa(struct ccp_op *op) +{ + u32 cr[6]; + + /* Fill out the register contents for REQ1 through REQ6 */ + cr[0] = (CCP_ENGINE_RSA << REQ1_ENGINE_SHIFT) + | (op->u.rsa.mod_size << REQ1_RSA_MOD_SIZE_SHIFT) + | (op->ksb_key << REQ1_KEY_KSB_SHIFT) + | REQ1_EOM; + cr[1] = op->u.rsa.input_len - 1; + cr[2] = ccp_addr_lo(&op->src.u.dma); + cr[3] = (op->ksb_ctx << REQ4_KSB_SHIFT) + | (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT) + | ccp_addr_hi(&op->src.u.dma); + cr[4] = ccp_addr_lo(&op->dst.u.dma); + cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT) + | ccp_addr_hi(&op->dst.u.dma); + + return ccp_do_cmd(op, cr, ARRAY_SIZE(cr)); +} + +static int ccp_perform_passthru(struct ccp_op *op) +{ + u32 cr[6]; + + /* Fill out the register contents for REQ1 through REQ6 */ + cr[0] = (CCP_ENGINE_PASSTHRU << REQ1_ENGINE_SHIFT) + | (op->u.passthru.bit_mod << REQ1_PT_BW_SHIFT) + | (op->u.passthru.byte_swap << REQ1_PT_BS_SHIFT); + + if (op->src.type == CCP_MEMTYPE_SYSTEM) + cr[1] = op->src.u.dma.length - 1; + else + cr[1] = op->dst.u.dma.length - 1; + + if (op->src.type == CCP_MEMTYPE_SYSTEM) { + cr[2] = ccp_addr_lo(&op->src.u.dma); + cr[3] = (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT) + | ccp_addr_hi(&op->src.u.dma); + + if (op->u.passthru.bit_mod != CCP_PASSTHRU_BITWISE_NOOP) + cr[3] |= (op->ksb_key << REQ4_KSB_SHIFT); + } else { + cr[2] = op->src.u.ksb * CCP_KSB_BYTES; + cr[3] = (CCP_MEMTYPE_KSB << REQ4_MEMTYPE_SHIFT); + } + + if (op->dst.type == CCP_MEMTYPE_SYSTEM) { + cr[4] = ccp_addr_lo(&op->dst.u.dma); + cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT) + | ccp_addr_hi(&op->dst.u.dma); + } else { + cr[4] = op->dst.u.ksb * CCP_KSB_BYTES; + cr[5] = (CCP_MEMTYPE_KSB << REQ6_MEMTYPE_SHIFT); + } + + if (op->eom) + cr[0] |= REQ1_EOM; + + return ccp_do_cmd(op, cr, ARRAY_SIZE(cr)); +} + +static int ccp_perform_ecc(struct ccp_op *op) +{ + u32 cr[6]; + + /* Fill out the register contents for REQ1 through REQ6 */ + cr[0] = REQ1_ECC_AFFINE_CONVERT + | (CCP_ENGINE_ECC << REQ1_ENGINE_SHIFT) + | (op->u.ecc.function << REQ1_ECC_FUNCTION_SHIFT) + | REQ1_EOM; + cr[1] = op->src.u.dma.length - 1; + cr[2] = ccp_addr_lo(&op->src.u.dma); + cr[3] = (CCP_MEMTYPE_SYSTEM << REQ4_MEMTYPE_SHIFT) + | ccp_addr_hi(&op->src.u.dma); + cr[4] = ccp_addr_lo(&op->dst.u.dma); + cr[5] = (CCP_MEMTYPE_SYSTEM << REQ6_MEMTYPE_SHIFT) + | ccp_addr_hi(&op->dst.u.dma); + + return ccp_do_cmd(op, cr, ARRAY_SIZE(cr)); +} + +static u32 ccp_alloc_ksb(struct ccp_device *ccp, unsigned int count) +{ + int start; + + for (;;) { + mutex_lock(&ccp->ksb_mutex); + + start = (u32)bitmap_find_next_zero_area(ccp->ksb, + ccp->ksb_count, + ccp->ksb_start, + count, 0); + if (start <= ccp->ksb_count) { + bitmap_set(ccp->ksb, start, count); + + mutex_unlock(&ccp->ksb_mutex); + break; + } + + ccp->ksb_avail = 0; + + mutex_unlock(&ccp->ksb_mutex); + + /* Wait for KSB entries to become available */ + if (wait_event_interruptible(ccp->ksb_queue, ccp->ksb_avail)) + return 0; + } + + return KSB_START + start; +} + +static void ccp_free_ksb(struct ccp_device *ccp, unsigned int start, + unsigned int count) +{ + if (!start) + return; + + mutex_lock(&ccp->ksb_mutex); + + bitmap_clear(ccp->ksb, start - KSB_START, count); + + ccp->ksb_avail = 1; + + mutex_unlock(&ccp->ksb_mutex); + + wake_up_interruptible_all(&ccp->ksb_queue); +} + +static u32 ccp_gen_jobid(struct ccp_device *ccp) +{ + return atomic_inc_return(&ccp->current_id) & CCP_JOBID_MASK; +} + +static void ccp_sg_free(struct ccp_sg_workarea *wa) +{ + if (wa->dma_count) + dma_unmap_sg(wa->dma_dev, wa->dma_sg, wa->nents, wa->dma_dir); + + wa->dma_count = 0; +} + +static int ccp_init_sg_workarea(struct ccp_sg_workarea *wa, struct device *dev, + struct scatterlist *sg, unsigned int len, + enum dma_data_direction dma_dir) +{ + memset(wa, 0, sizeof(*wa)); + + wa->sg = sg; + if (!sg) + return 0; + + wa->nents = sg_nents(sg); + wa->length = sg->length; + wa->bytes_left = len; + wa->sg_used = 0; + + if (len == 0) + return 0; + + if (dma_dir == DMA_NONE) + return 0; + + wa->dma_sg = sg; + wa->dma_dev = dev; + wa->dma_dir = dma_dir; + wa->dma_count = dma_map_sg(dev, sg, wa->nents, dma_dir); + if (!wa->dma_count) + return -ENOMEM; + + + return 0; +} + +static void ccp_update_sg_workarea(struct ccp_sg_workarea *wa, unsigned int len) +{ + unsigned int nbytes = min(len, wa->bytes_left); + + if (!wa->sg) + return; + + wa->sg_used += nbytes; + wa->bytes_left -= nbytes; + if (wa->sg_used == wa->sg->length) { + wa->sg = sg_next(wa->sg); + wa->sg_used = 0; + } +} + +static void ccp_dm_free(struct ccp_dm_workarea *wa) +{ + if (wa->length <= CCP_DMAPOOL_MAX_SIZE) { + if (wa->address) + dma_pool_free(wa->dma_pool, wa->address, + wa->dma.address); + } else { + if (wa->dma.address) + dma_unmap_single(wa->dev, wa->dma.address, wa->length, + wa->dma.dir); + kfree(wa->address); + } + + wa->address = NULL; + wa->dma.address = 0; +} + +static int ccp_init_dm_workarea(struct ccp_dm_workarea *wa, + struct ccp_cmd_queue *cmd_q, + unsigned int len, + enum dma_data_direction dir) +{ + memset(wa, 0, sizeof(*wa)); + + if (!len) + return 0; + + wa->dev = cmd_q->ccp->dev; + wa->length = len; + + if (len <= CCP_DMAPOOL_MAX_SIZE) { + wa->dma_pool = cmd_q->dma_pool; + + wa->address = dma_pool_alloc(wa->dma_pool, GFP_KERNEL, + &wa->dma.address); + if (!wa->address) + return -ENOMEM; + + wa->dma.length = CCP_DMAPOOL_MAX_SIZE; + + memset(wa->address, 0, CCP_DMAPOOL_MAX_SIZE); + } else { + wa->address = kzalloc(len, GFP_KERNEL); + if (!wa->address) + return -ENOMEM; + + wa->dma.address = dma_map_single(wa->dev, wa->address, len, + dir); + if (!wa->dma.address) + return -ENOMEM; + + wa->dma.length = len; + } + wa->dma.dir = dir; + + return 0; +} + +static void ccp_set_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset, + struct scatterlist *sg, unsigned int sg_offset, + unsigned int len) +{ + WARN_ON(!wa->address); + + scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len, + 0); +} + +static void ccp_get_dm_area(struct ccp_dm_workarea *wa, unsigned int wa_offset, + struct scatterlist *sg, unsigned int sg_offset, + unsigned int len) +{ + WARN_ON(!wa->address); + + scatterwalk_map_and_copy(wa->address + wa_offset, sg, sg_offset, len, + 1); +} + +static void ccp_reverse_set_dm_area(struct ccp_dm_workarea *wa, + struct scatterlist *sg, + unsigned int len, unsigned int se_len, + bool sign_extend) +{ + unsigned int nbytes, sg_offset, dm_offset, ksb_len, i; + u8 buffer[CCP_REVERSE_BUF_SIZE]; + + BUG_ON(se_len > sizeof(buffer)); + + sg_offset = len; + dm_offset = 0; + nbytes = len; + while (nbytes) { + ksb_len = min_t(unsigned int, nbytes, se_len); + sg_offset -= ksb_len; + + scatterwalk_map_and_copy(buffer, sg, sg_offset, ksb_len, 0); + for (i = 0; i < ksb_len; i++) + wa->address[dm_offset + i] = buffer[ksb_len - i - 1]; + + dm_offset += ksb_len; + nbytes -= ksb_len; + + if ((ksb_len != se_len) && sign_extend) { + /* Must sign-extend to nearest sign-extend length */ + if (wa->address[dm_offset - 1] & 0x80) + memset(wa->address + dm_offset, 0xff, + se_len - ksb_len); + } + } +} + +static void ccp_reverse_get_dm_area(struct ccp_dm_workarea *wa, + struct scatterlist *sg, + unsigned int len) +{ + unsigned int nbytes, sg_offset, dm_offset, ksb_len, i; + u8 buffer[CCP_REVERSE_BUF_SIZE]; + + sg_offset = 0; + dm_offset = len; + nbytes = len; + while (nbytes) { + ksb_len = min_t(unsigned int, nbytes, sizeof(buffer)); + dm_offset -= ksb_len; + + for (i = 0; i < ksb_len; i++) + buffer[ksb_len - i - 1] = wa->address[dm_offset + i]; + scatterwalk_map_and_copy(buffer, sg, sg_offset, ksb_len, 1); + + sg_offset += ksb_len; + nbytes -= ksb_len; + } +} + +static void ccp_free_data(struct ccp_data *data, struct ccp_cmd_queue *cmd_q) +{ + ccp_dm_free(&data->dm_wa); + ccp_sg_free(&data->sg_wa); +} + +static int ccp_init_data(struct ccp_data *data, struct ccp_cmd_queue *cmd_q, + struct scatterlist *sg, unsigned int sg_len, + unsigned int dm_len, + enum dma_data_direction dir) +{ + int ret; + + memset(data, 0, sizeof(*data)); + + ret = ccp_init_sg_workarea(&data->sg_wa, cmd_q->ccp->dev, sg, sg_len, + dir); + if (ret) + goto e_err; + + ret = ccp_init_dm_workarea(&data->dm_wa, cmd_q, dm_len, dir); + if (ret) + goto e_err; + + return 0; + +e_err: + ccp_free_data(data, cmd_q); + + return ret; +} + +static unsigned int ccp_queue_buf(struct ccp_data *data, unsigned int from) +{ + struct ccp_sg_workarea *sg_wa = &data->sg_wa; + struct ccp_dm_workarea *dm_wa = &data->dm_wa; + unsigned int buf_count, nbytes; + + /* Clear the buffer if setting it */ + if (!from) + memset(dm_wa->address, 0, dm_wa->length); + + if (!sg_wa->sg) + return 0; + + /* Perform the copy operation */ + nbytes = min(sg_wa->bytes_left, dm_wa->length); + scatterwalk_map_and_copy(dm_wa->address, sg_wa->sg, sg_wa->sg_used, + nbytes, from); + + /* Update the structures and generate the count */ + buf_count = 0; + while (sg_wa->bytes_left && (buf_count < dm_wa->length)) { + nbytes = min3(sg_wa->sg->length - sg_wa->sg_used, + dm_wa->length - buf_count, + sg_wa->bytes_left); + + buf_count += nbytes; + ccp_update_sg_workarea(sg_wa, nbytes); + } + + return buf_count; +} + +static unsigned int ccp_fill_queue_buf(struct ccp_data *data) +{ + return ccp_queue_buf(data, 0); +} + +static unsigned int ccp_empty_queue_buf(struct ccp_data *data) +{ + return ccp_queue_buf(data, 1); +} + +static void ccp_prepare_data(struct ccp_data *src, struct ccp_data *dst, + struct ccp_op *op, unsigned int block_size, + bool blocksize_op) +{ + unsigned int sg_src_len, sg_dst_len, op_len; + + /* The CCP can only DMA from/to one address each per operation. This + * requires that we find the smallest DMA area between the source + * and destination. + */ + sg_src_len = min(sg_dma_len(src->sg_wa.sg) - src->sg_wa.sg_used, + src->sg_wa.bytes_left); + + if (dst) { + sg_dst_len = min(sg_dma_len(dst->sg_wa.sg) - dst->sg_wa.sg_used, + src->sg_wa.bytes_left); + op_len = min(sg_src_len, sg_dst_len); + } else + op_len = sg_src_len; + + /* The data operation length will be at least block_size in length + * or the smaller of available sg room remaining for the source or + * the destination + */ + op_len = max(op_len, block_size); + + /* Unless we have to buffer data, there's no reason to wait */ + op->soc = 0; + + if (sg_src_len < block_size) { + /* Not enough data in the sg element, so it + * needs to be buffered into a blocksize chunk + */ + int cp_len = ccp_fill_queue_buf(src); + + op->soc = 1; + op->src.u.dma.address = src->dm_wa.dma.address; + op->src.u.dma.offset = 0; + op->src.u.dma.length = (blocksize_op) ? block_size : cp_len; + } else { + /* Enough data in the sg element, but we need to + * adjust for any previously copied data + */ + op->src.u.dma.address = sg_dma_address(src->sg_wa.sg); + op->src.u.dma.offset = src->sg_wa.sg_used; + op->src.u.dma.length = op_len & ~(block_size - 1); + + ccp_update_sg_workarea(&src->sg_wa, op->src.u.dma.length); + } + + if (dst) { + if (sg_dst_len < block_size) { + /* Not enough room in the sg element or we're on the + * last piece of data (when using padding), so the + * output needs to be buffered into a blocksize chunk + */ + op->soc = 1; + op->dst.u.dma.address = dst->dm_wa.dma.address; + op->dst.u.dma.offset = 0; + op->dst.u.dma.length = op->src.u.dma.length; + } else { + /* Enough room in the sg element, but we need to + * adjust for any previously used area + */ + op->dst.u.dma.address = sg_dma_address(dst->sg_wa.sg); + op->dst.u.dma.offset = dst->sg_wa.sg_used; + op->dst.u.dma.length = op->src.u.dma.length; + } + } +} + +static void ccp_process_data(struct ccp_data *src, struct ccp_data *dst, + struct ccp_op *op) +{ + op->init = 0; + + if (dst) { + if (op->dst.u.dma.address == dst->dm_wa.dma.address) + ccp_empty_queue_buf(dst); + else + ccp_update_sg_workarea(&dst->sg_wa, + op->dst.u.dma.length); + } +} + +static int ccp_copy_to_from_ksb(struct ccp_cmd_queue *cmd_q, + struct ccp_dm_workarea *wa, u32 jobid, u32 ksb, + u32 byte_swap, bool from) +{ + struct ccp_op op; + + memset(&op, 0, sizeof(op)); + + op.cmd_q = cmd_q; + op.jobid = jobid; + op.eom = 1; + + if (from) { + op.soc = 1; + op.src.type = CCP_MEMTYPE_KSB; + op.src.u.ksb = ksb; + op.dst.type = CCP_MEMTYPE_SYSTEM; + op.dst.u.dma.address = wa->dma.address; + op.dst.u.dma.length = wa->length; + } else { + op.src.type = CCP_MEMTYPE_SYSTEM; + op.src.u.dma.address = wa->dma.address; + op.src.u.dma.length = wa->length; + op.dst.type = CCP_MEMTYPE_KSB; + op.dst.u.ksb = ksb; + } + + op.u.passthru.byte_swap = byte_swap; + + return ccp_perform_passthru(&op); +} + +static int ccp_copy_to_ksb(struct ccp_cmd_queue *cmd_q, + struct ccp_dm_workarea *wa, u32 jobid, u32 ksb, + u32 byte_swap) +{ + return ccp_copy_to_from_ksb(cmd_q, wa, jobid, ksb, byte_swap, false); +} + +static int ccp_copy_from_ksb(struct ccp_cmd_queue *cmd_q, + struct ccp_dm_workarea *wa, u32 jobid, u32 ksb, + u32 byte_swap) +{ + return ccp_copy_to_from_ksb(cmd_q, wa, jobid, ksb, byte_swap, true); +} + +static int ccp_run_aes_cmac_cmd(struct ccp_cmd_queue *cmd_q, + struct ccp_cmd *cmd) +{ + struct ccp_aes_engine *aes = &cmd->u.aes; + struct ccp_dm_workarea key, ctx; + struct ccp_data src; + struct ccp_op op; + unsigned int dm_offset; + int ret; + + if (!((aes->key_len == AES_KEYSIZE_128) || + (aes->key_len == AES_KEYSIZE_192) || + (aes->key_len == AES_KEYSIZE_256))) + return -EINVAL; + + if (aes->src_len & (AES_BLOCK_SIZE - 1)) + return -EINVAL; + + if (aes->iv_len != AES_BLOCK_SIZE) + return -EINVAL; + + if (!aes->key || !aes->iv || !aes->src) + return -EINVAL; + + if (aes->cmac_final) { + if (aes->cmac_key_len != AES_BLOCK_SIZE) + return -EINVAL; + + if (!aes->cmac_key) + return -EINVAL; + } + + BUILD_BUG_ON(CCP_AES_KEY_KSB_COUNT != 1); + BUILD_BUG_ON(CCP_AES_CTX_KSB_COUNT != 1); + + ret = -EIO; + memset(&op, 0, sizeof(op)); + op.cmd_q = cmd_q; + op.jobid = ccp_gen_jobid(cmd_q->ccp); + op.ksb_key = cmd_q->ksb_key; + op.ksb_ctx = cmd_q->ksb_ctx; + op.init = 1; + op.u.aes.type = aes->type; + op.u.aes.mode = aes->mode; + op.u.aes.action = aes->action; + + /* All supported key sizes fit in a single (32-byte) KSB entry + * and must be in little endian format. Use the 256-bit byte + * swap passthru option to convert from big endian to little + * endian. + */ + ret = ccp_init_dm_workarea(&key, cmd_q, + CCP_AES_KEY_KSB_COUNT * CCP_KSB_BYTES, + DMA_TO_DEVICE); + if (ret) + return ret; + + dm_offset = CCP_KSB_BYTES - aes->key_len; + ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len); + ret = ccp_copy_to_ksb(cmd_q, &key, op.jobid, op.ksb_key, + CCP_PASSTHRU_BYTESWAP_256BIT); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_key; + } + + /* The AES context fits in a single (32-byte) KSB entry and + * must be in little endian format. Use the 256-bit byte swap + * passthru option to convert from big endian to little endian. + */ + ret = ccp_init_dm_workarea(&ctx, cmd_q, + CCP_AES_CTX_KSB_COUNT * CCP_KSB_BYTES, + DMA_BIDIRECTIONAL); + if (ret) + goto e_key; + + dm_offset = CCP_KSB_BYTES - AES_BLOCK_SIZE; + ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len); + ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx, + CCP_PASSTHRU_BYTESWAP_256BIT); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_ctx; + } + + /* Send data to the CCP AES engine */ + ret = ccp_init_data(&src, cmd_q, aes->src, aes->src_len, + AES_BLOCK_SIZE, DMA_TO_DEVICE); + if (ret) + goto e_ctx; + + while (src.sg_wa.bytes_left) { + ccp_prepare_data(&src, NULL, &op, AES_BLOCK_SIZE, true); + if (aes->cmac_final && !src.sg_wa.bytes_left) { + op.eom = 1; + + /* Push the K1/K2 key to the CCP now */ + ret = ccp_copy_from_ksb(cmd_q, &ctx, op.jobid, + op.ksb_ctx, + CCP_PASSTHRU_BYTESWAP_256BIT); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_src; + } + + ccp_set_dm_area(&ctx, 0, aes->cmac_key, 0, + aes->cmac_key_len); + ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx, + CCP_PASSTHRU_BYTESWAP_256BIT); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_src; + } + } + + ret = ccp_perform_aes(&op); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_src; + } + + ccp_process_data(&src, NULL, &op); + } + + /* Retrieve the AES context - convert from LE to BE using + * 32-byte (256-bit) byteswapping + */ + ret = ccp_copy_from_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx, + CCP_PASSTHRU_BYTESWAP_256BIT); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_src; + } + + /* ...but we only need AES_BLOCK_SIZE bytes */ + dm_offset = CCP_KSB_BYTES - AES_BLOCK_SIZE; + ccp_get_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len); + +e_src: + ccp_free_data(&src, cmd_q); + +e_ctx: + ccp_dm_free(&ctx); + +e_key: + ccp_dm_free(&key); + + return ret; +} + +static int ccp_run_aes_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +{ + struct ccp_aes_engine *aes = &cmd->u.aes; + struct ccp_dm_workarea key, ctx; + struct ccp_data src, dst; + struct ccp_op op; + unsigned int dm_offset; + bool in_place = false; + int ret; + + if (aes->mode == CCP_AES_MODE_CMAC) + return ccp_run_aes_cmac_cmd(cmd_q, cmd); + + if (!((aes->key_len == AES_KEYSIZE_128) || + (aes->key_len == AES_KEYSIZE_192) || + (aes->key_len == AES_KEYSIZE_256))) + return -EINVAL; + + if (((aes->mode == CCP_AES_MODE_ECB) || + (aes->mode == CCP_AES_MODE_CBC) || + (aes->mode == CCP_AES_MODE_CFB)) && + (aes->src_len & (AES_BLOCK_SIZE - 1))) + return -EINVAL; + + if (!aes->key || !aes->src || !aes->dst) + return -EINVAL; + + if (aes->mode != CCP_AES_MODE_ECB) { + if (aes->iv_len != AES_BLOCK_SIZE) + return -EINVAL; + + if (!aes->iv) + return -EINVAL; + } + + BUILD_BUG_ON(CCP_AES_KEY_KSB_COUNT != 1); + BUILD_BUG_ON(CCP_AES_CTX_KSB_COUNT != 1); + + ret = -EIO; + memset(&op, 0, sizeof(op)); + op.cmd_q = cmd_q; + op.jobid = ccp_gen_jobid(cmd_q->ccp); + op.ksb_key = cmd_q->ksb_key; + op.ksb_ctx = cmd_q->ksb_ctx; + op.init = (aes->mode == CCP_AES_MODE_ECB) ? 0 : 1; + op.u.aes.type = aes->type; + op.u.aes.mode = aes->mode; + op.u.aes.action = aes->action; + + /* All supported key sizes fit in a single (32-byte) KSB entry + * and must be in little endian format. Use the 256-bit byte + * swap passthru option to convert from big endian to little + * endian. + */ + ret = ccp_init_dm_workarea(&key, cmd_q, + CCP_AES_KEY_KSB_COUNT * CCP_KSB_BYTES, + DMA_TO_DEVICE); + if (ret) + return ret; + + dm_offset = CCP_KSB_BYTES - aes->key_len; + ccp_set_dm_area(&key, dm_offset, aes->key, 0, aes->key_len); + ret = ccp_copy_to_ksb(cmd_q, &key, op.jobid, op.ksb_key, + CCP_PASSTHRU_BYTESWAP_256BIT); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_key; + } + + /* The AES context fits in a single (32-byte) KSB entry and + * must be in little endian format. Use the 256-bit byte swap + * passthru option to convert from big endian to little endian. + */ + ret = ccp_init_dm_workarea(&ctx, cmd_q, + CCP_AES_CTX_KSB_COUNT * CCP_KSB_BYTES, + DMA_BIDIRECTIONAL); + if (ret) + goto e_key; + + if (aes->mode != CCP_AES_MODE_ECB) { + /* Load the AES context - conver to LE */ + dm_offset = CCP_KSB_BYTES - AES_BLOCK_SIZE; + ccp_set_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len); + ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx, + CCP_PASSTHRU_BYTESWAP_256BIT); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_ctx; + } + } + + /* Prepare the input and output data workareas. For in-place + * operations we need to set the dma direction to BIDIRECTIONAL + * and copy the src workarea to the dst workarea. + */ + if (sg_virt(aes->src) == sg_virt(aes->dst)) + in_place = true; + + ret = ccp_init_data(&src, cmd_q, aes->src, aes->src_len, + AES_BLOCK_SIZE, + in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); + if (ret) + goto e_ctx; + + if (in_place) + dst = src; + else { + ret = ccp_init_data(&dst, cmd_q, aes->dst, aes->src_len, + AES_BLOCK_SIZE, DMA_FROM_DEVICE); + if (ret) + goto e_src; + } + + /* Send data to the CCP AES engine */ + while (src.sg_wa.bytes_left) { + ccp_prepare_data(&src, &dst, &op, AES_BLOCK_SIZE, true); + if (!src.sg_wa.bytes_left) { + op.eom = 1; + + /* Since we don't retrieve the AES context in ECB + * mode we have to wait for the operation to complete + * on the last piece of data + */ + if (aes->mode == CCP_AES_MODE_ECB) + op.soc = 1; + } + + ret = ccp_perform_aes(&op); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_dst; + } + + ccp_process_data(&src, &dst, &op); + } + + if (aes->mode != CCP_AES_MODE_ECB) { + /* Retrieve the AES context - convert from LE to BE using + * 32-byte (256-bit) byteswapping + */ + ret = ccp_copy_from_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx, + CCP_PASSTHRU_BYTESWAP_256BIT); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_dst; + } + + /* ...but we only need AES_BLOCK_SIZE bytes */ + dm_offset = CCP_KSB_BYTES - AES_BLOCK_SIZE; + ccp_get_dm_area(&ctx, dm_offset, aes->iv, 0, aes->iv_len); + } + +e_dst: + if (!in_place) + ccp_free_data(&dst, cmd_q); + +e_src: + ccp_free_data(&src, cmd_q); + +e_ctx: + ccp_dm_free(&ctx); + +e_key: + ccp_dm_free(&key); + + return ret; +} + +static int ccp_run_xts_aes_cmd(struct ccp_cmd_queue *cmd_q, + struct ccp_cmd *cmd) +{ + struct ccp_xts_aes_engine *xts = &cmd->u.xts; + struct ccp_dm_workarea key, ctx; + struct ccp_data src, dst; + struct ccp_op op; + unsigned int unit_size, dm_offset; + bool in_place = false; + int ret; + + switch (xts->unit_size) { + case CCP_XTS_AES_UNIT_SIZE_16: + unit_size = 16; + break; + case CCP_XTS_AES_UNIT_SIZE_512: + unit_size = 512; + break; + case CCP_XTS_AES_UNIT_SIZE_1024: + unit_size = 1024; + break; + case CCP_XTS_AES_UNIT_SIZE_2048: + unit_size = 2048; + break; + case CCP_XTS_AES_UNIT_SIZE_4096: + unit_size = 4096; + break; + + default: + return -EINVAL; + } + + if (xts->key_len != AES_KEYSIZE_128) + return -EINVAL; + + if (!xts->final && (xts->src_len & (AES_BLOCK_SIZE - 1))) + return -EINVAL; + + if (xts->iv_len != AES_BLOCK_SIZE) + return -EINVAL; + + if (!xts->key || !xts->iv || !xts->src || !xts->dst) + return -EINVAL; + + BUILD_BUG_ON(CCP_XTS_AES_KEY_KSB_COUNT != 1); + BUILD_BUG_ON(CCP_XTS_AES_CTX_KSB_COUNT != 1); + + ret = -EIO; + memset(&op, 0, sizeof(op)); + op.cmd_q = cmd_q; + op.jobid = ccp_gen_jobid(cmd_q->ccp); + op.ksb_key = cmd_q->ksb_key; + op.ksb_ctx = cmd_q->ksb_ctx; + op.init = 1; + op.u.xts.action = xts->action; + op.u.xts.unit_size = xts->unit_size; + + /* All supported key sizes fit in a single (32-byte) KSB entry + * and must be in little endian format. Use the 256-bit byte + * swap passthru option to convert from big endian to little + * endian. + */ + ret = ccp_init_dm_workarea(&key, cmd_q, + CCP_XTS_AES_KEY_KSB_COUNT * CCP_KSB_BYTES, + DMA_TO_DEVICE); + if (ret) + return ret; + + dm_offset = CCP_KSB_BYTES - AES_KEYSIZE_128; + ccp_set_dm_area(&key, dm_offset, xts->key, 0, xts->key_len); + ccp_set_dm_area(&key, 0, xts->key, dm_offset, xts->key_len); + ret = ccp_copy_to_ksb(cmd_q, &key, op.jobid, op.ksb_key, + CCP_PASSTHRU_BYTESWAP_256BIT); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_key; + } + + /* The AES context fits in a single (32-byte) KSB entry and + * for XTS is already in little endian format so no byte swapping + * is needed. + */ + ret = ccp_init_dm_workarea(&ctx, cmd_q, + CCP_XTS_AES_CTX_KSB_COUNT * CCP_KSB_BYTES, + DMA_BIDIRECTIONAL); + if (ret) + goto e_key; + + ccp_set_dm_area(&ctx, 0, xts->iv, 0, xts->iv_len); + ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx, + CCP_PASSTHRU_BYTESWAP_NOOP); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_ctx; + } + + /* Prepare the input and output data workareas. For in-place + * operations we need to set the dma direction to BIDIRECTIONAL + * and copy the src workarea to the dst workarea. + */ + if (sg_virt(xts->src) == sg_virt(xts->dst)) + in_place = true; + + ret = ccp_init_data(&src, cmd_q, xts->src, xts->src_len, + unit_size, + in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); + if (ret) + goto e_ctx; + + if (in_place) + dst = src; + else { + ret = ccp_init_data(&dst, cmd_q, xts->dst, xts->src_len, + unit_size, DMA_FROM_DEVICE); + if (ret) + goto e_src; + } + + /* Send data to the CCP AES engine */ + while (src.sg_wa.bytes_left) { + ccp_prepare_data(&src, &dst, &op, unit_size, true); + if (!src.sg_wa.bytes_left) + op.eom = 1; + + ret = ccp_perform_xts_aes(&op); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_dst; + } + + ccp_process_data(&src, &dst, &op); + } + + /* Retrieve the AES context - convert from LE to BE using + * 32-byte (256-bit) byteswapping + */ + ret = ccp_copy_from_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx, + CCP_PASSTHRU_BYTESWAP_256BIT); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_dst; + } + + /* ...but we only need AES_BLOCK_SIZE bytes */ + dm_offset = CCP_KSB_BYTES - AES_BLOCK_SIZE; + ccp_get_dm_area(&ctx, dm_offset, xts->iv, 0, xts->iv_len); + +e_dst: + if (!in_place) + ccp_free_data(&dst, cmd_q); + +e_src: + ccp_free_data(&src, cmd_q); + +e_ctx: + ccp_dm_free(&ctx); + +e_key: + ccp_dm_free(&key); + + return ret; +} + +static int ccp_run_sha_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +{ + struct ccp_sha_engine *sha = &cmd->u.sha; + struct ccp_dm_workarea ctx; + struct ccp_data src; + struct ccp_op op; + int ret; + + if (sha->ctx_len != CCP_SHA_CTXSIZE) + return -EINVAL; + + if (!sha->ctx) + return -EINVAL; + + if (!sha->final && (sha->src_len & (CCP_SHA_BLOCKSIZE - 1))) + return -EINVAL; + + if (!sha->src_len) { + const u8 *sha_zero; + + /* Not final, just return */ + if (!sha->final) + return 0; + + /* CCP can't do a zero length sha operation so the caller + * must buffer the data. + */ + if (sha->msg_bits) + return -EINVAL; + + /* A sha operation for a message with a total length of zero, + * return known result. + */ + switch (sha->type) { + case CCP_SHA_TYPE_1: + sha_zero = ccp_sha1_zero; + break; + case CCP_SHA_TYPE_224: + sha_zero = ccp_sha224_zero; + break; + case CCP_SHA_TYPE_256: + sha_zero = ccp_sha256_zero; + break; + default: + return -EINVAL; + } + + scatterwalk_map_and_copy((void *)sha_zero, sha->ctx, 0, + sha->ctx_len, 1); + + return 0; + } + + if (!sha->src) + return -EINVAL; + + BUILD_BUG_ON(CCP_SHA_KSB_COUNT != 1); + + memset(&op, 0, sizeof(op)); + op.cmd_q = cmd_q; + op.jobid = ccp_gen_jobid(cmd_q->ccp); + op.ksb_ctx = cmd_q->ksb_ctx; + op.u.sha.type = sha->type; + op.u.sha.msg_bits = sha->msg_bits; + + /* The SHA context fits in a single (32-byte) KSB entry and + * must be in little endian format. Use the 256-bit byte swap + * passthru option to convert from big endian to little endian. + */ + ret = ccp_init_dm_workarea(&ctx, cmd_q, + CCP_SHA_KSB_COUNT * CCP_KSB_BYTES, + DMA_BIDIRECTIONAL); + if (ret) + return ret; + + ccp_set_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len); + ret = ccp_copy_to_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx, + CCP_PASSTHRU_BYTESWAP_256BIT); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_ctx; + } + + /* Send data to the CCP SHA engine */ + ret = ccp_init_data(&src, cmd_q, sha->src, sha->src_len, + CCP_SHA_BLOCKSIZE, DMA_TO_DEVICE); + if (ret) + goto e_ctx; + + while (src.sg_wa.bytes_left) { + ccp_prepare_data(&src, NULL, &op, CCP_SHA_BLOCKSIZE, false); + if (sha->final && !src.sg_wa.bytes_left) + op.eom = 1; + + ret = ccp_perform_sha(&op); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_data; + } + + ccp_process_data(&src, NULL, &op); + } + + /* Retrieve the SHA context - convert from LE to BE using + * 32-byte (256-bit) byteswapping to BE + */ + ret = ccp_copy_from_ksb(cmd_q, &ctx, op.jobid, op.ksb_ctx, + CCP_PASSTHRU_BYTESWAP_256BIT); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_data; + } + + ccp_get_dm_area(&ctx, 0, sha->ctx, 0, sha->ctx_len); + +e_data: + ccp_free_data(&src, cmd_q); + +e_ctx: + ccp_dm_free(&ctx); + + return ret; +} + +static int ccp_run_rsa_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +{ + struct ccp_rsa_engine *rsa = &cmd->u.rsa; + struct ccp_dm_workarea exp, src; + struct ccp_data dst; + struct ccp_op op; + unsigned int ksb_count, i_len, o_len; + int ret; + + if (rsa->key_size > CCP_RSA_MAX_WIDTH) + return -EINVAL; + + if (!rsa->exp || !rsa->mod || !rsa->src || !rsa->dst) + return -EINVAL; + + /* The RSA modulus must precede the message being acted upon, so + * it must be copied to a DMA area where the message and the + * modulus can be concatenated. Therefore the input buffer + * length required is twice the output buffer length (which + * must be a multiple of 256-bits). + */ + o_len = ((rsa->key_size + 255) / 256) * 32; + i_len = o_len * 2; + + ksb_count = o_len / CCP_KSB_BYTES; + + memset(&op, 0, sizeof(op)); + op.cmd_q = cmd_q; + op.jobid = ccp_gen_jobid(cmd_q->ccp); + op.ksb_key = ccp_alloc_ksb(cmd_q->ccp, ksb_count); + if (!op.ksb_key) + return -EIO; + + /* The RSA exponent may span multiple (32-byte) KSB entries and must + * be in little endian format. Reverse copy each 32-byte chunk + * of the exponent (En chunk to E0 chunk, E(n-1) chunk to E1 chunk) + * and each byte within that chunk and do not perform any byte swap + * operations on the passthru operation. + */ + ret = ccp_init_dm_workarea(&exp, cmd_q, o_len, DMA_TO_DEVICE); + if (ret) + goto e_ksb; + + ccp_reverse_set_dm_area(&exp, rsa->exp, rsa->exp_len, CCP_KSB_BYTES, + true); + ret = ccp_copy_to_ksb(cmd_q, &exp, op.jobid, op.ksb_key, + CCP_PASSTHRU_BYTESWAP_NOOP); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_exp; + } + + /* Concatenate the modulus and the message. Both the modulus and + * the operands must be in little endian format. Since the input + * is in big endian format it must be converted. + */ + ret = ccp_init_dm_workarea(&src, cmd_q, i_len, DMA_TO_DEVICE); + if (ret) + goto e_exp; + + ccp_reverse_set_dm_area(&src, rsa->mod, rsa->mod_len, CCP_KSB_BYTES, + true); + src.address += o_len; /* Adjust the address for the copy operation */ + ccp_reverse_set_dm_area(&src, rsa->src, rsa->src_len, CCP_KSB_BYTES, + true); + src.address -= o_len; /* Reset the address to original value */ + + /* Prepare the output area for the operation */ + ret = ccp_init_data(&dst, cmd_q, rsa->dst, rsa->mod_len, + o_len, DMA_FROM_DEVICE); + if (ret) + goto e_src; + + op.soc = 1; + op.src.u.dma.address = src.dma.address; + op.src.u.dma.offset = 0; + op.src.u.dma.length = i_len; + op.dst.u.dma.address = dst.dm_wa.dma.address; + op.dst.u.dma.offset = 0; + op.dst.u.dma.length = o_len; + + op.u.rsa.mod_size = rsa->key_size; + op.u.rsa.input_len = i_len; + + ret = ccp_perform_rsa(&op); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_dst; + } + + ccp_reverse_get_dm_area(&dst.dm_wa, rsa->dst, rsa->mod_len); + +e_dst: + ccp_free_data(&dst, cmd_q); + +e_src: + ccp_dm_free(&src); + +e_exp: + ccp_dm_free(&exp); + +e_ksb: + ccp_free_ksb(cmd_q->ccp, op.ksb_key, ksb_count); + + return ret; +} + +static int ccp_run_passthru_cmd(struct ccp_cmd_queue *cmd_q, + struct ccp_cmd *cmd) +{ + struct ccp_passthru_engine *pt = &cmd->u.passthru; + struct ccp_dm_workarea mask; + struct ccp_data src, dst; + struct ccp_op op; + bool in_place = false; + unsigned int i; + int ret; + + if (!pt->final && (pt->src_len & (CCP_PASSTHRU_BLOCKSIZE - 1))) + return -EINVAL; + + if (!pt->src || !pt->dst) + return -EINVAL; + + if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) { + if (pt->mask_len != CCP_PASSTHRU_MASKSIZE) + return -EINVAL; + if (!pt->mask) + return -EINVAL; + } + + BUILD_BUG_ON(CCP_PASSTHRU_KSB_COUNT != 1); + + memset(&op, 0, sizeof(op)); + op.cmd_q = cmd_q; + op.jobid = ccp_gen_jobid(cmd_q->ccp); + + if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) { + /* Load the mask */ + op.ksb_key = cmd_q->ksb_key; + + ret = ccp_init_dm_workarea(&mask, cmd_q, + CCP_PASSTHRU_KSB_COUNT * + CCP_KSB_BYTES, + DMA_TO_DEVICE); + if (ret) + return ret; + + ccp_set_dm_area(&mask, 0, pt->mask, 0, pt->mask_len); + ret = ccp_copy_to_ksb(cmd_q, &mask, op.jobid, op.ksb_key, + CCP_PASSTHRU_BYTESWAP_NOOP); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_mask; + } + } + + /* Prepare the input and output data workareas. For in-place + * operations we need to set the dma direction to BIDIRECTIONAL + * and copy the src workarea to the dst workarea. + */ + if (sg_virt(pt->src) == sg_virt(pt->dst)) + in_place = true; + + ret = ccp_init_data(&src, cmd_q, pt->src, pt->src_len, + CCP_PASSTHRU_MASKSIZE, + in_place ? DMA_BIDIRECTIONAL : DMA_TO_DEVICE); + if (ret) + goto e_mask; + + if (in_place) + dst = src; + else { + ret = ccp_init_data(&dst, cmd_q, pt->dst, pt->src_len, + CCP_PASSTHRU_MASKSIZE, DMA_FROM_DEVICE); + if (ret) + goto e_src; + } + + /* Send data to the CCP Passthru engine + * Because the CCP engine works on a single source and destination + * dma address at a time, each entry in the source scatterlist + * (after the dma_map_sg call) must be less than or equal to the + * (remaining) length in the destination scatterlist entry and the + * length must be a multiple of CCP_PASSTHRU_BLOCKSIZE + */ + dst.sg_wa.sg_used = 0; + for (i = 1; i <= src.sg_wa.dma_count; i++) { + if (!dst.sg_wa.sg || + (dst.sg_wa.sg->length < src.sg_wa.sg->length)) { + ret = -EINVAL; + goto e_dst; + } + + if (i == src.sg_wa.dma_count) { + op.eom = 1; + op.soc = 1; + } + + op.src.type = CCP_MEMTYPE_SYSTEM; + op.src.u.dma.address = sg_dma_address(src.sg_wa.sg); + op.src.u.dma.offset = 0; + op.src.u.dma.length = sg_dma_len(src.sg_wa.sg); + + op.dst.type = CCP_MEMTYPE_SYSTEM; + op.dst.u.dma.address = sg_dma_address(dst.sg_wa.sg); + op.src.u.dma.offset = dst.sg_wa.sg_used; + op.src.u.dma.length = op.src.u.dma.length; + + ret = ccp_perform_passthru(&op); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_dst; + } + + dst.sg_wa.sg_used += src.sg_wa.sg->length; + if (dst.sg_wa.sg_used == dst.sg_wa.sg->length) { + dst.sg_wa.sg = sg_next(dst.sg_wa.sg); + dst.sg_wa.sg_used = 0; + } + src.sg_wa.sg = sg_next(src.sg_wa.sg); + } + +e_dst: + if (!in_place) + ccp_free_data(&dst, cmd_q); + +e_src: + ccp_free_data(&src, cmd_q); + +e_mask: + if (pt->bit_mod != CCP_PASSTHRU_BITWISE_NOOP) + ccp_dm_free(&mask); + + return ret; +} + +static int ccp_run_ecc_mm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +{ + struct ccp_ecc_engine *ecc = &cmd->u.ecc; + struct ccp_dm_workarea src, dst; + struct ccp_op op; + int ret; + u8 *save; + + if (!ecc->u.mm.operand_1 || + (ecc->u.mm.operand_1_len > CCP_ECC_MODULUS_BYTES)) + return -EINVAL; + + if (ecc->function != CCP_ECC_FUNCTION_MINV_384BIT) + if (!ecc->u.mm.operand_2 || + (ecc->u.mm.operand_2_len > CCP_ECC_MODULUS_BYTES)) + return -EINVAL; + + if (!ecc->u.mm.result || + (ecc->u.mm.result_len < CCP_ECC_MODULUS_BYTES)) + return -EINVAL; + + memset(&op, 0, sizeof(op)); + op.cmd_q = cmd_q; + op.jobid = ccp_gen_jobid(cmd_q->ccp); + + /* Concatenate the modulus and the operands. Both the modulus and + * the operands must be in little endian format. Since the input + * is in big endian format it must be converted and placed in a + * fixed length buffer. + */ + ret = ccp_init_dm_workarea(&src, cmd_q, CCP_ECC_SRC_BUF_SIZE, + DMA_TO_DEVICE); + if (ret) + return ret; + + /* Save the workarea address since it is updated in order to perform + * the concatenation + */ + save = src.address; + + /* Copy the ECC modulus */ + ccp_reverse_set_dm_area(&src, ecc->mod, ecc->mod_len, + CCP_ECC_OPERAND_SIZE, true); + src.address += CCP_ECC_OPERAND_SIZE; + + /* Copy the first operand */ + ccp_reverse_set_dm_area(&src, ecc->u.mm.operand_1, + ecc->u.mm.operand_1_len, + CCP_ECC_OPERAND_SIZE, true); + src.address += CCP_ECC_OPERAND_SIZE; + + if (ecc->function != CCP_ECC_FUNCTION_MINV_384BIT) { + /* Copy the second operand */ + ccp_reverse_set_dm_area(&src, ecc->u.mm.operand_2, + ecc->u.mm.operand_2_len, + CCP_ECC_OPERAND_SIZE, true); + src.address += CCP_ECC_OPERAND_SIZE; + } + + /* Restore the workarea address */ + src.address = save; + + /* Prepare the output area for the operation */ + ret = ccp_init_dm_workarea(&dst, cmd_q, CCP_ECC_DST_BUF_SIZE, + DMA_FROM_DEVICE); + if (ret) + goto e_src; + + op.soc = 1; + op.src.u.dma.address = src.dma.address; + op.src.u.dma.offset = 0; + op.src.u.dma.length = src.length; + op.dst.u.dma.address = dst.dma.address; + op.dst.u.dma.offset = 0; + op.dst.u.dma.length = dst.length; + + op.u.ecc.function = cmd->u.ecc.function; + + ret = ccp_perform_ecc(&op); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_dst; + } + + ecc->ecc_result = le16_to_cpup( + (const __le16 *)(dst.address + CCP_ECC_RESULT_OFFSET)); + if (!(ecc->ecc_result & CCP_ECC_RESULT_SUCCESS)) { + ret = -EIO; + goto e_dst; + } + + /* Save the ECC result */ + ccp_reverse_get_dm_area(&dst, ecc->u.mm.result, CCP_ECC_MODULUS_BYTES); + +e_dst: + ccp_dm_free(&dst); + +e_src: + ccp_dm_free(&src); + + return ret; +} + +static int ccp_run_ecc_pm_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +{ + struct ccp_ecc_engine *ecc = &cmd->u.ecc; + struct ccp_dm_workarea src, dst; + struct ccp_op op; + int ret; + u8 *save; + + if (!ecc->u.pm.point_1.x || + (ecc->u.pm.point_1.x_len > CCP_ECC_MODULUS_BYTES) || + !ecc->u.pm.point_1.y || + (ecc->u.pm.point_1.y_len > CCP_ECC_MODULUS_BYTES)) + return -EINVAL; + + if (ecc->function == CCP_ECC_FUNCTION_PADD_384BIT) { + if (!ecc->u.pm.point_2.x || + (ecc->u.pm.point_2.x_len > CCP_ECC_MODULUS_BYTES) || + !ecc->u.pm.point_2.y || + (ecc->u.pm.point_2.y_len > CCP_ECC_MODULUS_BYTES)) + return -EINVAL; + } else { + if (!ecc->u.pm.domain_a || + (ecc->u.pm.domain_a_len > CCP_ECC_MODULUS_BYTES)) + return -EINVAL; + + if (ecc->function == CCP_ECC_FUNCTION_PMUL_384BIT) + if (!ecc->u.pm.scalar || + (ecc->u.pm.scalar_len > CCP_ECC_MODULUS_BYTES)) + return -EINVAL; + } + + if (!ecc->u.pm.result.x || + (ecc->u.pm.result.x_len < CCP_ECC_MODULUS_BYTES) || + !ecc->u.pm.result.y || + (ecc->u.pm.result.y_len < CCP_ECC_MODULUS_BYTES)) + return -EINVAL; + + memset(&op, 0, sizeof(op)); + op.cmd_q = cmd_q; + op.jobid = ccp_gen_jobid(cmd_q->ccp); + + /* Concatenate the modulus and the operands. Both the modulus and + * the operands must be in little endian format. Since the input + * is in big endian format it must be converted and placed in a + * fixed length buffer. + */ + ret = ccp_init_dm_workarea(&src, cmd_q, CCP_ECC_SRC_BUF_SIZE, + DMA_TO_DEVICE); + if (ret) + return ret; + + /* Save the workarea address since it is updated in order to perform + * the concatenation + */ + save = src.address; + + /* Copy the ECC modulus */ + ccp_reverse_set_dm_area(&src, ecc->mod, ecc->mod_len, + CCP_ECC_OPERAND_SIZE, true); + src.address += CCP_ECC_OPERAND_SIZE; + + /* Copy the first point X and Y coordinate */ + ccp_reverse_set_dm_area(&src, ecc->u.pm.point_1.x, + ecc->u.pm.point_1.x_len, + CCP_ECC_OPERAND_SIZE, true); + src.address += CCP_ECC_OPERAND_SIZE; + ccp_reverse_set_dm_area(&src, ecc->u.pm.point_1.y, + ecc->u.pm.point_1.y_len, + CCP_ECC_OPERAND_SIZE, true); + src.address += CCP_ECC_OPERAND_SIZE; + + /* Set the first point Z coordianate to 1 */ + *(src.address) = 0x01; + src.address += CCP_ECC_OPERAND_SIZE; + + if (ecc->function == CCP_ECC_FUNCTION_PADD_384BIT) { + /* Copy the second point X and Y coordinate */ + ccp_reverse_set_dm_area(&src, ecc->u.pm.point_2.x, + ecc->u.pm.point_2.x_len, + CCP_ECC_OPERAND_SIZE, true); + src.address += CCP_ECC_OPERAND_SIZE; + ccp_reverse_set_dm_area(&src, ecc->u.pm.point_2.y, + ecc->u.pm.point_2.y_len, + CCP_ECC_OPERAND_SIZE, true); + src.address += CCP_ECC_OPERAND_SIZE; + + /* Set the second point Z coordianate to 1 */ + *(src.address) = 0x01; + src.address += CCP_ECC_OPERAND_SIZE; + } else { + /* Copy the Domain "a" parameter */ + ccp_reverse_set_dm_area(&src, ecc->u.pm.domain_a, + ecc->u.pm.domain_a_len, + CCP_ECC_OPERAND_SIZE, true); + src.address += CCP_ECC_OPERAND_SIZE; + + if (ecc->function == CCP_ECC_FUNCTION_PMUL_384BIT) { + /* Copy the scalar value */ + ccp_reverse_set_dm_area(&src, ecc->u.pm.scalar, + ecc->u.pm.scalar_len, + CCP_ECC_OPERAND_SIZE, true); + src.address += CCP_ECC_OPERAND_SIZE; + } + } + + /* Restore the workarea address */ + src.address = save; + + /* Prepare the output area for the operation */ + ret = ccp_init_dm_workarea(&dst, cmd_q, CCP_ECC_DST_BUF_SIZE, + DMA_FROM_DEVICE); + if (ret) + goto e_src; + + op.soc = 1; + op.src.u.dma.address = src.dma.address; + op.src.u.dma.offset = 0; + op.src.u.dma.length = src.length; + op.dst.u.dma.address = dst.dma.address; + op.dst.u.dma.offset = 0; + op.dst.u.dma.length = dst.length; + + op.u.ecc.function = cmd->u.ecc.function; + + ret = ccp_perform_ecc(&op); + if (ret) { + cmd->engine_error = cmd_q->cmd_error; + goto e_dst; + } + + ecc->ecc_result = le16_to_cpup( + (const __le16 *)(dst.address + CCP_ECC_RESULT_OFFSET)); + if (!(ecc->ecc_result & CCP_ECC_RESULT_SUCCESS)) { + ret = -EIO; + goto e_dst; + } + + /* Save the workarea address since it is updated as we walk through + * to copy the point math result + */ + save = dst.address; + + /* Save the ECC result X and Y coordinates */ + ccp_reverse_get_dm_area(&dst, ecc->u.pm.result.x, + CCP_ECC_MODULUS_BYTES); + dst.address += CCP_ECC_OUTPUT_SIZE; + ccp_reverse_get_dm_area(&dst, ecc->u.pm.result.y, + CCP_ECC_MODULUS_BYTES); + dst.address += CCP_ECC_OUTPUT_SIZE; + + /* Restore the workarea address */ + dst.address = save; + +e_dst: + ccp_dm_free(&dst); + +e_src: + ccp_dm_free(&src); + + return ret; +} + +static int ccp_run_ecc_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +{ + struct ccp_ecc_engine *ecc = &cmd->u.ecc; + + ecc->ecc_result = 0; + + if (!ecc->mod || + (ecc->mod_len > CCP_ECC_MODULUS_BYTES)) + return -EINVAL; + + switch (ecc->function) { + case CCP_ECC_FUNCTION_MMUL_384BIT: + case CCP_ECC_FUNCTION_MADD_384BIT: + case CCP_ECC_FUNCTION_MINV_384BIT: + return ccp_run_ecc_mm_cmd(cmd_q, cmd); + + case CCP_ECC_FUNCTION_PADD_384BIT: + case CCP_ECC_FUNCTION_PMUL_384BIT: + case CCP_ECC_FUNCTION_PDBL_384BIT: + return ccp_run_ecc_pm_cmd(cmd_q, cmd); + + default: + return -EINVAL; + } +} + +int ccp_run_cmd(struct ccp_cmd_queue *cmd_q, struct ccp_cmd *cmd) +{ + int ret; + + cmd->engine_error = 0; + cmd_q->cmd_error = 0; + cmd_q->int_rcvd = 0; + cmd_q->free_slots = CMD_Q_DEPTH(ioread32(cmd_q->reg_status)); + + switch (cmd->engine) { + case CCP_ENGINE_AES: + ret = ccp_run_aes_cmd(cmd_q, cmd); + break; + case CCP_ENGINE_XTS_AES_128: + ret = ccp_run_xts_aes_cmd(cmd_q, cmd); + break; + case CCP_ENGINE_SHA: + ret = ccp_run_sha_cmd(cmd_q, cmd); + break; + case CCP_ENGINE_RSA: + ret = ccp_run_rsa_cmd(cmd_q, cmd); + break; + case CCP_ENGINE_PASSTHRU: + ret = ccp_run_passthru_cmd(cmd_q, cmd); + break; + case CCP_ENGINE_ECC: + ret = ccp_run_ecc_cmd(cmd_q, cmd); + break; + default: + ret = -EINVAL; + } + + return ret; +} diff --git a/drivers/crypto/ccp/ccp-pci.c b/drivers/crypto/ccp/ccp-pci.c new file mode 100644 index 000000000000..1fbeaf1856a8 --- /dev/null +++ b/drivers/crypto/ccp/ccp-pci.c @@ -0,0 +1,360 @@ +/* + * AMD Cryptographic Coprocessor (CCP) driver + * + * Copyright (C) 2013 Advanced Micro Devices, Inc. + * + * Author: Tom Lendacky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ccp-dev.h" + +#define IO_BAR 2 +#define MSIX_VECTORS 2 + +struct ccp_msix { + u32 vector; + char name[16]; +}; + +struct ccp_pci { + int msix_count; + struct ccp_msix msix[MSIX_VECTORS]; +}; + +static int ccp_get_msix_irqs(struct ccp_device *ccp) +{ + struct ccp_pci *ccp_pci = ccp->dev_specific; + struct device *dev = ccp->dev; + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + struct msix_entry msix_entry[MSIX_VECTORS]; + unsigned int name_len = sizeof(ccp_pci->msix[0].name) - 1; + int v, ret; + + for (v = 0; v < ARRAY_SIZE(msix_entry); v++) + msix_entry[v].entry = v; + + while ((ret = pci_enable_msix(pdev, msix_entry, v)) > 0) + v = ret; + if (ret) + return ret; + + ccp_pci->msix_count = v; + for (v = 0; v < ccp_pci->msix_count; v++) { + /* Set the interrupt names and request the irqs */ + snprintf(ccp_pci->msix[v].name, name_len, "ccp-%u", v); + ccp_pci->msix[v].vector = msix_entry[v].vector; + ret = request_irq(ccp_pci->msix[v].vector, ccp_irq_handler, + 0, ccp_pci->msix[v].name, dev); + if (ret) { + dev_notice(dev, "unable to allocate MSI-X IRQ (%d)\n", + ret); + goto e_irq; + } + } + + return 0; + +e_irq: + while (v--) + free_irq(ccp_pci->msix[v].vector, dev); + + pci_disable_msix(pdev); + + ccp_pci->msix_count = 0; + + return ret; +} + +static int ccp_get_msi_irq(struct ccp_device *ccp) +{ + struct device *dev = ccp->dev; + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + int ret; + + ret = pci_enable_msi(pdev); + if (ret) + return ret; + + ret = request_irq(pdev->irq, ccp_irq_handler, 0, "ccp", dev); + if (ret) { + dev_notice(dev, "unable to allocate MSI IRQ (%d)\n", ret); + goto e_msi; + } + + return 0; + +e_msi: + pci_disable_msi(pdev); + + return ret; +} + +static int ccp_get_irqs(struct ccp_device *ccp) +{ + struct device *dev = ccp->dev; + int ret; + + ret = ccp_get_msix_irqs(ccp); + if (!ret) + return 0; + + /* Couldn't get MSI-X vectors, try MSI */ + dev_notice(dev, "could not enable MSI-X (%d), trying MSI\n", ret); + ret = ccp_get_msi_irq(ccp); + if (!ret) + return 0; + + /* Couldn't get MSI interrupt */ + dev_notice(dev, "could not enable MSI (%d)\n", ret); + + return ret; +} + +static void ccp_free_irqs(struct ccp_device *ccp) +{ + struct ccp_pci *ccp_pci = ccp->dev_specific; + struct device *dev = ccp->dev; + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + + if (ccp_pci->msix_count) { + while (ccp_pci->msix_count--) + free_irq(ccp_pci->msix[ccp_pci->msix_count].vector, + dev); + pci_disable_msix(pdev); + } else { + free_irq(pdev->irq, dev); + pci_disable_msi(pdev); + } +} + +static int ccp_find_mmio_area(struct ccp_device *ccp) +{ + struct device *dev = ccp->dev; + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + resource_size_t io_len; + unsigned long io_flags; + int bar; + + io_flags = pci_resource_flags(pdev, IO_BAR); + io_len = pci_resource_len(pdev, IO_BAR); + if ((io_flags & IORESOURCE_MEM) && (io_len >= (IO_OFFSET + 0x800))) + return IO_BAR; + + for (bar = 0; bar < PCI_STD_RESOURCE_END; bar++) { + io_flags = pci_resource_flags(pdev, bar); + io_len = pci_resource_len(pdev, bar); + if ((io_flags & IORESOURCE_MEM) && + (io_len >= (IO_OFFSET + 0x800))) + return bar; + } + + return -EIO; +} + +static int ccp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct ccp_device *ccp; + struct ccp_pci *ccp_pci; + struct device *dev = &pdev->dev; + unsigned int bar; + int ret; + + ret = -ENOMEM; + ccp = ccp_alloc_struct(dev); + if (!ccp) + goto e_err; + + ccp_pci = kzalloc(sizeof(*ccp_pci), GFP_KERNEL); + if (!ccp_pci) { + ret = -ENOMEM; + goto e_free1; + } + ccp->dev_specific = ccp_pci; + ccp->get_irq = ccp_get_irqs; + ccp->free_irq = ccp_free_irqs; + + ret = pci_request_regions(pdev, "ccp"); + if (ret) { + dev_err(dev, "pci_request_regions failed (%d)\n", ret); + goto e_free2; + } + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(dev, "pci_enable_device failed (%d)\n", ret); + goto e_regions; + } + + pci_set_master(pdev); + + ret = ccp_find_mmio_area(ccp); + if (ret < 0) + goto e_device; + bar = ret; + + ret = -EIO; + ccp->io_map = pci_iomap(pdev, bar, 0); + if (ccp->io_map == NULL) { + dev_err(dev, "pci_iomap failed\n"); + goto e_device; + } + ccp->io_regs = ccp->io_map + IO_OFFSET; + + ret = dma_set_mask(dev, DMA_BIT_MASK(48)); + if (ret == 0) { + ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(48)); + if (ret) { + dev_err(dev, + "pci_set_consistent_dma_mask failed (%d)\n", + ret); + goto e_bar0; + } + } else { + ret = dma_set_mask(dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(dev, "pci_set_dma_mask failed (%d)\n", ret); + goto e_bar0; + } + } + + dev_set_drvdata(dev, ccp); + + ret = ccp_init(ccp); + if (ret) + goto e_bar0; + + dev_notice(dev, "enabled\n"); + + return 0; + +e_bar0: + pci_iounmap(pdev, ccp->io_map); + +e_device: + pci_disable_device(pdev); + dev_set_drvdata(dev, NULL); + +e_regions: + pci_release_regions(pdev); + +e_free2: + kfree(ccp_pci); + +e_free1: + kfree(ccp); + +e_err: + dev_notice(dev, "initialization failed\n"); + return ret; +} + +static void ccp_pci_remove(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + struct ccp_device *ccp = dev_get_drvdata(dev); + + ccp_destroy(ccp); + + pci_iounmap(pdev, ccp->io_map); + + pci_disable_device(pdev); + dev_set_drvdata(dev, NULL); + + pci_release_regions(pdev); + + kfree(ccp); + + dev_notice(dev, "disabled\n"); +} + +#ifdef CONFIG_PM +static int ccp_pci_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct device *dev = &pdev->dev; + struct ccp_device *ccp = dev_get_drvdata(dev); + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&ccp->cmd_lock, flags); + + ccp->suspending = 1; + + /* Wake all the queue kthreads to prepare for suspend */ + for (i = 0; i < ccp->cmd_q_count; i++) + wake_up_process(ccp->cmd_q[i].kthread); + + spin_unlock_irqrestore(&ccp->cmd_lock, flags); + + /* Wait for all queue kthreads to say they're done */ + while (!ccp_queues_suspended(ccp)) + wait_event_interruptible(ccp->suspend_queue, + ccp_queues_suspended(ccp)); + + return 0; +} + +static int ccp_pci_resume(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + struct ccp_device *ccp = dev_get_drvdata(dev); + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&ccp->cmd_lock, flags); + + ccp->suspending = 0; + + /* Wake up all the kthreads */ + for (i = 0; i < ccp->cmd_q_count; i++) { + ccp->cmd_q[i].suspended = 0; + wake_up_process(ccp->cmd_q[i].kthread); + } + + spin_unlock_irqrestore(&ccp->cmd_lock, flags); + + return 0; +} +#endif + +static DEFINE_PCI_DEVICE_TABLE(ccp_pci_table) = { + { PCI_VDEVICE(AMD, 0x1537), }, + /* Last entry must be zero */ + { 0, } +}; +MODULE_DEVICE_TABLE(pci, ccp_pci_table); + +static struct pci_driver ccp_pci_driver = { + .name = "AMD Cryptographic Coprocessor", + .id_table = ccp_pci_table, + .probe = ccp_pci_probe, + .remove = ccp_pci_remove, +#ifdef CONFIG_PM + .suspend = ccp_pci_suspend, + .resume = ccp_pci_resume, +#endif +}; + +int ccp_pci_init(void) +{ + return pci_register_driver(&ccp_pci_driver); +} + +void ccp_pci_exit(void) +{ + pci_unregister_driver(&ccp_pci_driver); +} diff --git a/include/linux/ccp.h b/include/linux/ccp.h new file mode 100644 index 000000000000..e8c23493ab4b --- /dev/null +++ b/include/linux/ccp.h @@ -0,0 +1,525 @@ +/* + * AMD Cryptographic Coprocessor (CCP) driver + * + * Copyright (C) 2013 Advanced Micro Devices, Inc. + * + * Author: Tom Lendacky + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __CPP_H__ +#define __CPP_H__ + +#include +#include +#include +#include +#include + + +struct ccp_device; +struct ccp_cmd; + +/** + * ccp_enqueue_cmd - queue an operation for processing by the CCP + * + * @cmd: ccp_cmd struct to be processed + * + * Refer to the ccp_cmd struct below for required fields. + * + * Queue a cmd to be processed by the CCP. If queueing the cmd + * would exceed the defined length of the cmd queue the cmd will + * only be queued if the CCP_CMD_MAY_BACKLOG flag is set and will + * result in a return code of -EBUSY. + * + * The callback routine specified in the ccp_cmd struct will be + * called to notify the caller of completion (if the cmd was not + * backlogged) or advancement out of the backlog. If the cmd has + * advanced out of the backlog the "err" value of the callback + * will be -EINPROGRESS. Any other "err" value during callback is + * the result of the operation. + * + * The cmd has been successfully queued if: + * the return code is -EINPROGRESS or + * the return code is -EBUSY and CCP_CMD_MAY_BACKLOG flag is set + */ +int ccp_enqueue_cmd(struct ccp_cmd *cmd); + + +/***** AES engine *****/ +/** + * ccp_aes_type - AES key size + * + * @CCP_AES_TYPE_128: 128-bit key + * @CCP_AES_TYPE_192: 192-bit key + * @CCP_AES_TYPE_256: 256-bit key + */ +enum ccp_aes_type { + CCP_AES_TYPE_128 = 0, + CCP_AES_TYPE_192, + CCP_AES_TYPE_256, + CCP_AES_TYPE__LAST, +}; + +/** + * ccp_aes_mode - AES operation mode + * + * @CCP_AES_MODE_ECB: ECB mode + * @CCP_AES_MODE_CBC: CBC mode + * @CCP_AES_MODE_OFB: OFB mode + * @CCP_AES_MODE_CFB: CFB mode + * @CCP_AES_MODE_CTR: CTR mode + * @CCP_AES_MODE_CMAC: CMAC mode + */ +enum ccp_aes_mode { + CCP_AES_MODE_ECB = 0, + CCP_AES_MODE_CBC, + CCP_AES_MODE_OFB, + CCP_AES_MODE_CFB, + CCP_AES_MODE_CTR, + CCP_AES_MODE_CMAC, + CCP_AES_MODE__LAST, +}; + +/** + * ccp_aes_mode - AES operation mode + * + * @CCP_AES_ACTION_DECRYPT: AES decrypt operation + * @CCP_AES_ACTION_ENCRYPT: AES encrypt operation + */ +enum ccp_aes_action { + CCP_AES_ACTION_DECRYPT = 0, + CCP_AES_ACTION_ENCRYPT, + CCP_AES_ACTION__LAST, +}; + +/** + * struct ccp_aes_engine - CCP AES operation + * @type: AES operation key size + * @mode: AES operation mode + * @action: AES operation (decrypt/encrypt) + * @key: key to be used for this AES operation + * @key_len: length in bytes of key + * @iv: IV to be used for this AES operation + * @iv_len: length in bytes of iv + * @src: data to be used for this operation + * @dst: data produced by this operation + * @src_len: length in bytes of data used for this operation + * @cmac_final: indicates final operation when running in CMAC mode + * @cmac_key: K1/K2 key used in final CMAC operation + * @cmac_key_len: length in bytes of cmac_key + * + * Variables required to be set when calling ccp_enqueue_cmd(): + * - type, mode, action, key, key_len, src, dst, src_len + * - iv, iv_len for any mode other than ECB + * - cmac_final for CMAC mode + * - cmac_key, cmac_key_len for CMAC mode if cmac_final is non-zero + * + * The iv variable is used as both input and output. On completion of the + * AES operation the new IV overwrites the old IV. + */ +struct ccp_aes_engine { + enum ccp_aes_type type; + enum ccp_aes_mode mode; + enum ccp_aes_action action; + + struct scatterlist *key; + u32 key_len; /* In bytes */ + + struct scatterlist *iv; + u32 iv_len; /* In bytes */ + + struct scatterlist *src, *dst; + u32 src_len; /* In bytes */ + + u32 cmac_final; /* Indicates final cmac cmd */ + struct scatterlist *cmac_key; /* K1/K2 cmac key required for + * final cmac cmd */ + u32 cmac_key_len; /* In bytes */ +}; + +/***** XTS-AES engine *****/ +/** + * ccp_xts_aes_unit_size - XTS unit size + * + * @CCP_XTS_AES_UNIT_SIZE_16: Unit size of 16 bytes + * @CCP_XTS_AES_UNIT_SIZE_512: Unit size of 512 bytes + * @CCP_XTS_AES_UNIT_SIZE_1024: Unit size of 1024 bytes + * @CCP_XTS_AES_UNIT_SIZE_2048: Unit size of 2048 bytes + * @CCP_XTS_AES_UNIT_SIZE_4096: Unit size of 4096 bytes + */ +enum ccp_xts_aes_unit_size { + CCP_XTS_AES_UNIT_SIZE_16 = 0, + CCP_XTS_AES_UNIT_SIZE_512, + CCP_XTS_AES_UNIT_SIZE_1024, + CCP_XTS_AES_UNIT_SIZE_2048, + CCP_XTS_AES_UNIT_SIZE_4096, + CCP_XTS_AES_UNIT_SIZE__LAST, +}; + +/** + * struct ccp_xts_aes_engine - CCP XTS AES operation + * @action: AES operation (decrypt/encrypt) + * @unit_size: unit size of the XTS operation + * @key: key to be used for this XTS AES operation + * @key_len: length in bytes of key + * @iv: IV to be used for this XTS AES operation + * @iv_len: length in bytes of iv + * @src: data to be used for this operation + * @dst: data produced by this operation + * @src_len: length in bytes of data used for this operation + * @final: indicates final XTS operation + * + * Variables required to be set when calling ccp_enqueue_cmd(): + * - action, unit_size, key, key_len, iv, iv_len, src, dst, src_len, final + * + * The iv variable is used as both input and output. On completion of the + * AES operation the new IV overwrites the old IV. + */ +struct ccp_xts_aes_engine { + enum ccp_aes_action action; + enum ccp_xts_aes_unit_size unit_size; + + struct scatterlist *key; + u32 key_len; /* In bytes */ + + struct scatterlist *iv; + u32 iv_len; /* In bytes */ + + struct scatterlist *src, *dst; + u32 src_len; /* In bytes */ + + u32 final; +}; + +/***** SHA engine *****/ +#define CCP_SHA_BLOCKSIZE SHA256_BLOCK_SIZE +#define CCP_SHA_CTXSIZE SHA256_DIGEST_SIZE + +/** + * ccp_sha_type - type of SHA operation + * + * @CCP_SHA_TYPE_1: SHA-1 operation + * @CCP_SHA_TYPE_224: SHA-224 operation + * @CCP_SHA_TYPE_256: SHA-256 operation + */ +enum ccp_sha_type { + CCP_SHA_TYPE_1 = 1, + CCP_SHA_TYPE_224, + CCP_SHA_TYPE_256, + CCP_SHA_TYPE__LAST, +}; + +/** + * struct ccp_sha_engine - CCP SHA operation + * @type: Type of SHA operation + * @ctx: current hash value + * @ctx_len: length in bytes of hash value + * @src: data to be used for this operation + * @src_len: length in bytes of data used for this operation + * @final: indicates final SHA operation + * @msg_bits: total length of the message in bits used in final SHA operation + * + * Variables required to be set when calling ccp_enqueue_cmd(): + * - type, ctx, ctx_len, src, src_len, final + * - msg_bits if final is non-zero + * + * The ctx variable is used as both input and output. On completion of the + * SHA operation the new hash value overwrites the old hash value. + */ +struct ccp_sha_engine { + enum ccp_sha_type type; + + struct scatterlist *ctx; + u32 ctx_len; /* In bytes */ + + struct scatterlist *src; + u32 src_len; /* In bytes */ + + u32 final; /* Indicates final sha cmd */ + u64 msg_bits; /* Message length in bits required for + * final sha cmd */ +}; + +/***** RSA engine *****/ +/** + * struct ccp_rsa_engine - CCP RSA operation + * @key_size: length in bits of RSA key + * @exp: RSA exponent + * @exp_len: length in bytes of exponent + * @mod: RSA modulus + * @mod_len: length in bytes of modulus + * @src: data to be used for this operation + * @dst: data produced by this operation + * @src_len: length in bytes of data used for this operation + * + * Variables required to be set when calling ccp_enqueue_cmd(): + * - key_size, exp, exp_len, mod, mod_len, src, dst, src_len + */ +struct ccp_rsa_engine { + u32 key_size; /* In bits */ + + struct scatterlist *exp; + u32 exp_len; /* In bytes */ + + struct scatterlist *mod; + u32 mod_len; /* In bytes */ + + struct scatterlist *src, *dst; + u32 src_len; /* In bytes */ +}; + +/***** Passthru engine *****/ +/** + * ccp_passthru_bitwise - type of bitwise passthru operation + * + * @CCP_PASSTHRU_BITWISE_NOOP: no bitwise operation performed + * @CCP_PASSTHRU_BITWISE_AND: perform bitwise AND of src with mask + * @CCP_PASSTHRU_BITWISE_OR: perform bitwise OR of src with mask + * @CCP_PASSTHRU_BITWISE_XOR: perform bitwise XOR of src with mask + * @CCP_PASSTHRU_BITWISE_MASK: overwrite with mask + */ +enum ccp_passthru_bitwise { + CCP_PASSTHRU_BITWISE_NOOP = 0, + CCP_PASSTHRU_BITWISE_AND, + CCP_PASSTHRU_BITWISE_OR, + CCP_PASSTHRU_BITWISE_XOR, + CCP_PASSTHRU_BITWISE_MASK, + CCP_PASSTHRU_BITWISE__LAST, +}; + +/** + * ccp_passthru_byteswap - type of byteswap passthru operation + * + * @CCP_PASSTHRU_BYTESWAP_NOOP: no byte swapping performed + * @CCP_PASSTHRU_BYTESWAP_32BIT: swap bytes within 32-bit words + * @CCP_PASSTHRU_BYTESWAP_256BIT: swap bytes within 256-bit words + */ +enum ccp_passthru_byteswap { + CCP_PASSTHRU_BYTESWAP_NOOP = 0, + CCP_PASSTHRU_BYTESWAP_32BIT, + CCP_PASSTHRU_BYTESWAP_256BIT, + CCP_PASSTHRU_BYTESWAP__LAST, +}; + +/** + * struct ccp_passthru_engine - CCP pass-through operation + * @bit_mod: bitwise operation to perform + * @byte_swap: byteswap operation to perform + * @mask: mask to be applied to data + * @mask_len: length in bytes of mask + * @src: data to be used for this operation + * @dst: data produced by this operation + * @src_len: length in bytes of data used for this operation + * @final: indicate final pass-through operation + * + * Variables required to be set when calling ccp_enqueue_cmd(): + * - bit_mod, byte_swap, src, dst, src_len + * - mask, mask_len if bit_mod is not CCP_PASSTHRU_BITWISE_NOOP + */ +struct ccp_passthru_engine { + enum ccp_passthru_bitwise bit_mod; + enum ccp_passthru_byteswap byte_swap; + + struct scatterlist *mask; + u32 mask_len; /* In bytes */ + + struct scatterlist *src, *dst; + u32 src_len; /* In bytes */ + + u32 final; +}; + +/***** ECC engine *****/ +#define CCP_ECC_MODULUS_BYTES 48 /* 384-bits */ +#define CCP_ECC_MAX_OPERANDS 6 +#define CCP_ECC_MAX_OUTPUTS 3 + +/** + * ccp_ecc_function - type of ECC function + * + * @CCP_ECC_FUNCTION_MMUL_384BIT: 384-bit modular multiplication + * @CCP_ECC_FUNCTION_MADD_384BIT: 384-bit modular addition + * @CCP_ECC_FUNCTION_MINV_384BIT: 384-bit multiplicative inverse + * @CCP_ECC_FUNCTION_PADD_384BIT: 384-bit point addition + * @CCP_ECC_FUNCTION_PMUL_384BIT: 384-bit point multiplication + * @CCP_ECC_FUNCTION_PDBL_384BIT: 384-bit point doubling + */ +enum ccp_ecc_function { + CCP_ECC_FUNCTION_MMUL_384BIT = 0, + CCP_ECC_FUNCTION_MADD_384BIT, + CCP_ECC_FUNCTION_MINV_384BIT, + CCP_ECC_FUNCTION_PADD_384BIT, + CCP_ECC_FUNCTION_PMUL_384BIT, + CCP_ECC_FUNCTION_PDBL_384BIT, +}; + +/** + * struct ccp_ecc_modular_math - CCP ECC modular math parameters + * @operand_1: first operand for the modular math operation + * @operand_1_len: length of the first operand + * @operand_2: second operand for the modular math operation + * (not used for CCP_ECC_FUNCTION_MINV_384BIT) + * @operand_2_len: length of the second operand + * (not used for CCP_ECC_FUNCTION_MINV_384BIT) + * @result: result of the modular math operation + * @result_len: length of the supplied result buffer + */ +struct ccp_ecc_modular_math { + struct scatterlist *operand_1; + unsigned int operand_1_len; /* In bytes */ + + struct scatterlist *operand_2; + unsigned int operand_2_len; /* In bytes */ + + struct scatterlist *result; + unsigned int result_len; /* In bytes */ +}; + +/** + * struct ccp_ecc_point - CCP ECC point definition + * @x: the x coordinate of the ECC point + * @x_len: the length of the x coordinate + * @y: the y coordinate of the ECC point + * @y_len: the length of the y coordinate + */ +struct ccp_ecc_point { + struct scatterlist *x; + unsigned int x_len; /* In bytes */ + + struct scatterlist *y; + unsigned int y_len; /* In bytes */ +}; + +/** + * struct ccp_ecc_point_math - CCP ECC point math parameters + * @point_1: the first point of the ECC point math operation + * @point_2: the second point of the ECC point math operation + * (only used for CCP_ECC_FUNCTION_PADD_384BIT) + * @domain_a: the a parameter of the ECC curve + * @domain_a_len: the length of the a parameter + * @scalar: the scalar parameter for the point match operation + * (only used for CCP_ECC_FUNCTION_PMUL_384BIT) + * @scalar_len: the length of the scalar parameter + * (only used for CCP_ECC_FUNCTION_PMUL_384BIT) + * @result: the point resulting from the point math operation + */ +struct ccp_ecc_point_math { + struct ccp_ecc_point point_1; + struct ccp_ecc_point point_2; + + struct scatterlist *domain_a; + unsigned int domain_a_len; /* In bytes */ + + struct scatterlist *scalar; + unsigned int scalar_len; /* In bytes */ + + struct ccp_ecc_point result; +}; + +/** + * struct ccp_ecc_engine - CCP ECC operation + * @function: ECC function to perform + * @mod: ECC modulus + * @mod_len: length in bytes of modulus + * @mm: module math parameters + * @pm: point math parameters + * @ecc_result: result of the ECC operation + * + * Variables required to be set when calling ccp_enqueue_cmd(): + * - function, mod, mod_len + * - operand, operand_len, operand_count, output, output_len, output_count + * - ecc_result + */ +struct ccp_ecc_engine { + enum ccp_ecc_function function; + + struct scatterlist *mod; + u32 mod_len; /* In bytes */ + + union { + struct ccp_ecc_modular_math mm; + struct ccp_ecc_point_math pm; + } u; + + u16 ecc_result; +}; + + +/** + * ccp_engine - CCP operation identifiers + * + * @CCP_ENGINE_AES: AES operation + * @CCP_ENGINE_XTS_AES: 128-bit XTS AES operation + * @CCP_ENGINE_RSVD1: unused + * @CCP_ENGINE_SHA: SHA operation + * @CCP_ENGINE_RSA: RSA operation + * @CCP_ENGINE_PASSTHRU: pass-through operation + * @CCP_ENGINE_ZLIB_DECOMPRESS: unused + * @CCP_ENGINE_ECC: ECC operation + */ +enum ccp_engine { + CCP_ENGINE_AES = 0, + CCP_ENGINE_XTS_AES_128, + CCP_ENGINE_RSVD1, + CCP_ENGINE_SHA, + CCP_ENGINE_RSA, + CCP_ENGINE_PASSTHRU, + CCP_ENGINE_ZLIB_DECOMPRESS, + CCP_ENGINE_ECC, + CCP_ENGINE__LAST, +}; + +/* Flag values for flags member of ccp_cmd */ +#define CCP_CMD_MAY_BACKLOG 0x00000001 + +/** + * struct ccp_cmd - CPP operation request + * @entry: list element (ccp driver use only) + * @work: work element used for callbacks (ccp driver use only) + * @ccp: CCP device to be run on (ccp driver use only) + * @ret: operation return code (ccp driver use only) + * @flags: cmd processing flags + * @engine: CCP operation to perform + * @engine_error: CCP engine return code + * @u: engine specific structures, refer to specific engine struct below + * @callback: operation completion callback function + * @data: parameter value to be supplied to the callback function + * + * Variables required to be set when calling ccp_enqueue_cmd(): + * - engine, callback + * - See the operation structures below for what is required for each + * operation. + */ +struct ccp_cmd { + /* The list_head, work_struct, ccp and ret variables are for use + * by the CCP driver only. + */ + struct list_head entry; + struct work_struct work; + struct ccp_device *ccp; + int ret; + + u32 flags; + + enum ccp_engine engine; + u32 engine_error; + + union { + struct ccp_aes_engine aes; + struct ccp_xts_aes_engine xts; + struct ccp_sha_engine sha; + struct ccp_rsa_engine rsa; + struct ccp_passthru_engine passthru; + struct ccp_ecc_engine ecc; + } u; + + /* Completion callback support */ + void (*callback)(void *data, int err); + void *data; +}; + +#endif -- cgit v1.2.3-59-g8ed1b From fe8c8a126806fea4465c43d62a1f9d273a572bf5 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Mon, 25 Nov 2013 22:00:41 -0200 Subject: crypto: more robust crypto_memneq Disabling compiler optimizations can be fragile, since a new optimization could be added to -O0 or -Os that breaks the assumptions the code is making. Instead of disabling compiler optimizations, use a dummy inline assembly (based on RELOC_HIDE) to block the problematic kinds of optimization, while still allowing other optimizations to be applied to the code. The dummy inline assembly is added after every OR, and has the accumulator variable as its input and output. The compiler is forced to assume that the dummy inline assembly could both depend on the accumulator variable and change the accumulator variable, so it is forced to compute the value correctly before the inline assembly, and cannot assume anything about its value after the inline assembly. This change should be enough to make crypto_memneq work correctly (with data-independent timing) even if it is inlined at its call sites. That can be done later in a followup patch. Compile-tested on x86_64. Signed-off-by: Cesar Eduardo Barros Acked-by: Daniel Borkmann Signed-off-by: Herbert Xu --- crypto/Makefile | 5 --- crypto/memneq.c | 79 +++++++++++++++++++++++++++++------------- include/linux/compiler-gcc.h | 3 ++ include/linux/compiler-intel.h | 7 ++++ include/linux/compiler.h | 4 +++ 5 files changed, 68 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/crypto/Makefile b/crypto/Makefile index 989c510da8cc..b29402a7b9b5 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -2,11 +2,6 @@ # Cryptographic API # -# memneq MUST be built with -Os or -O0 to prevent early-return optimizations -# that will defeat memneq's actual purpose to prevent timing attacks. -CFLAGS_REMOVE_memneq.o := -O1 -O2 -O3 -CFLAGS_memneq.o := -Os - obj-$(CONFIG_CRYPTO) += crypto.o crypto-y := api.o cipher.o compress.o memneq.o diff --git a/crypto/memneq.c b/crypto/memneq.c index cd0162221c14..570f6f3401ce 100644 --- a/crypto/memneq.c +++ b/crypto/memneq.c @@ -72,6 +72,7 @@ __crypto_memneq_generic(const void *a, const void *b, size_t size) #if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) while (size >= sizeof(unsigned long)) { neq |= *(unsigned long *)a ^ *(unsigned long *)b; + OPTIMIZER_HIDE_VAR(neq); a += sizeof(unsigned long); b += sizeof(unsigned long); size -= sizeof(unsigned long); @@ -79,6 +80,7 @@ __crypto_memneq_generic(const void *a, const void *b, size_t size) #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ while (size > 0) { neq |= *(unsigned char *)a ^ *(unsigned char *)b; + OPTIMIZER_HIDE_VAR(neq); a += 1; b += 1; size -= 1; @@ -89,33 +91,60 @@ __crypto_memneq_generic(const void *a, const void *b, size_t size) /* Loop-free fast-path for frequently used 16-byte size */ static inline unsigned long __crypto_memneq_16(const void *a, const void *b) { + unsigned long neq = 0; + #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - if (sizeof(unsigned long) == 8) - return ((*(unsigned long *)(a) ^ *(unsigned long *)(b)) - | (*(unsigned long *)(a+8) ^ *(unsigned long *)(b+8))); - else if (sizeof(unsigned int) == 4) - return ((*(unsigned int *)(a) ^ *(unsigned int *)(b)) - | (*(unsigned int *)(a+4) ^ *(unsigned int *)(b+4)) - | (*(unsigned int *)(a+8) ^ *(unsigned int *)(b+8)) - | (*(unsigned int *)(a+12) ^ *(unsigned int *)(b+12))); - else + if (sizeof(unsigned long) == 8) { + neq |= *(unsigned long *)(a) ^ *(unsigned long *)(b); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned long *)(a+8) ^ *(unsigned long *)(b+8); + OPTIMIZER_HIDE_VAR(neq); + } else if (sizeof(unsigned int) == 4) { + neq |= *(unsigned int *)(a) ^ *(unsigned int *)(b); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned int *)(a+4) ^ *(unsigned int *)(b+4); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned int *)(a+8) ^ *(unsigned int *)(b+8); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned int *)(a+12) ^ *(unsigned int *)(b+12); + OPTIMIZER_HIDE_VAR(neq); + } else { #endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ - return ((*(unsigned char *)(a) ^ *(unsigned char *)(b)) - | (*(unsigned char *)(a+1) ^ *(unsigned char *)(b+1)) - | (*(unsigned char *)(a+2) ^ *(unsigned char *)(b+2)) - | (*(unsigned char *)(a+3) ^ *(unsigned char *)(b+3)) - | (*(unsigned char *)(a+4) ^ *(unsigned char *)(b+4)) - | (*(unsigned char *)(a+5) ^ *(unsigned char *)(b+5)) - | (*(unsigned char *)(a+6) ^ *(unsigned char *)(b+6)) - | (*(unsigned char *)(a+7) ^ *(unsigned char *)(b+7)) - | (*(unsigned char *)(a+8) ^ *(unsigned char *)(b+8)) - | (*(unsigned char *)(a+9) ^ *(unsigned char *)(b+9)) - | (*(unsigned char *)(a+10) ^ *(unsigned char *)(b+10)) - | (*(unsigned char *)(a+11) ^ *(unsigned char *)(b+11)) - | (*(unsigned char *)(a+12) ^ *(unsigned char *)(b+12)) - | (*(unsigned char *)(a+13) ^ *(unsigned char *)(b+13)) - | (*(unsigned char *)(a+14) ^ *(unsigned char *)(b+14)) - | (*(unsigned char *)(a+15) ^ *(unsigned char *)(b+15))); + neq |= *(unsigned char *)(a) ^ *(unsigned char *)(b); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+1) ^ *(unsigned char *)(b+1); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+2) ^ *(unsigned char *)(b+2); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+3) ^ *(unsigned char *)(b+3); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+4) ^ *(unsigned char *)(b+4); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+5) ^ *(unsigned char *)(b+5); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+6) ^ *(unsigned char *)(b+6); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+7) ^ *(unsigned char *)(b+7); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+8) ^ *(unsigned char *)(b+8); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+9) ^ *(unsigned char *)(b+9); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+10) ^ *(unsigned char *)(b+10); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+11) ^ *(unsigned char *)(b+11); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+12) ^ *(unsigned char *)(b+12); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+13) ^ *(unsigned char *)(b+13); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+14) ^ *(unsigned char *)(b+14); + OPTIMIZER_HIDE_VAR(neq); + neq |= *(unsigned char *)(a+15) ^ *(unsigned char *)(b+15); + OPTIMIZER_HIDE_VAR(neq); + } + + return neq; } /* Compare two areas of memory without leaking timing information, diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 24545cd90a25..02ae99e8e6d3 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h @@ -37,6 +37,9 @@ __asm__ ("" : "=r"(__ptr) : "0"(ptr)); \ (typeof(ptr)) (__ptr + (off)); }) +/* Make the optimizer believe the variable can be manipulated arbitrarily. */ +#define OPTIMIZER_HIDE_VAR(var) __asm__ ("" : "=r" (var) : "0" (var)) + #ifdef __CHECKER__ #define __must_be_array(arr) 0 #else diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h index 973ce10c40b6..e784f5707749 100644 --- a/include/linux/compiler-intel.h +++ b/include/linux/compiler-intel.h @@ -15,6 +15,7 @@ */ #undef barrier #undef RELOC_HIDE +#undef OPTIMIZER_HIDE_VAR #define barrier() __memory_barrier() @@ -23,6 +24,12 @@ __ptr = (unsigned long) (ptr); \ (typeof(ptr)) (__ptr + (off)); }) +/* This should act as an optimization barrier on var. + * Given that this compiler does not have inline assembly, a compiler barrier + * is the best we can do. + */ +#define OPTIMIZER_HIDE_VAR(var) barrier() + /* Intel ECC compiler doesn't support __builtin_types_compatible_p() */ #define __must_be_array(a) 0 diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 92669cd182a6..a2329c5e6206 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -170,6 +170,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); (typeof(ptr)) (__ptr + (off)); }) #endif +#ifndef OPTIMIZER_HIDE_VAR +#define OPTIMIZER_HIDE_VAR(var) barrier() +#endif + /* Not-quite-unique ID. */ #ifndef __UNIQUE_ID # define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__) -- cgit v1.2.3-59-g8ed1b From 6e0755b08dd6a3b5260fafc6969268c2ba261300 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 5 Dec 2013 12:28:03 -0500 Subject: cgroup: remove cftype->read(), ->read_map() and ->write() In preparation of conversion to kernfs, cgroup file handling is being consolidated so that it can be easily mapped to the seq_file based interface of kernfs. After recent updates, ->read() and ->read_map() don't have any user left and ->write() never had any user. Remove them. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- include/linux/cgroup.h | 25 ------------------------- kernel/cgroup.c | 26 ++++---------------------- 2 files changed, 4 insertions(+), 47 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 50d8cc37498b..53e11da6e357 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -386,16 +386,6 @@ struct css_set { struct rcu_head rcu_head; }; -/* - * cgroup_map_cb is an abstract callback API for reporting map-valued - * control files - */ - -struct cgroup_map_cb { - int (*fill)(struct cgroup_map_cb *cb, const char *key, u64 value); - void *state; -}; - /* * struct cftype: handler definitions for cgroup control files * @@ -444,9 +434,6 @@ struct cftype { struct cgroup_subsys *ss; int (*open)(struct inode *inode, struct file *file); - ssize_t (*read)(struct cgroup_subsys_state *css, struct cftype *cft, - struct file *file, - char __user *buf, size_t nbytes, loff_t *ppos); /* * read_u64() is a shortcut for the common case of returning a * single integer. Use it in place of read() @@ -456,14 +443,6 @@ struct cftype { * read_s64() is a signed version of read_u64() */ s64 (*read_s64)(struct cgroup_subsys_state *css, struct cftype *cft); - /* - * read_map() is used for defining a map of key/value - * pairs. It should call cb->fill(cb, key, value) for each - * entry. The key/value pairs (and their ordering) should not - * change between reboots. - */ - int (*read_map)(struct cgroup_subsys_state *css, struct cftype *cft, - struct cgroup_map_cb *cb); /* * read_seq_string() is used for outputting a simple sequence * using seqfile. @@ -471,10 +450,6 @@ struct cftype { int (*read_seq_string)(struct cgroup_subsys_state *css, struct cftype *cft, struct seq_file *m); - ssize_t (*write)(struct cgroup_subsys_state *css, struct cftype *cft, - struct file *file, - const char __user *buf, size_t nbytes, loff_t *ppos); - /* * write_u64() is a shortcut for the common case of accepting * a single integer (as parsed by simple_strtoull) from diff --git a/kernel/cgroup.c b/kernel/cgroup.c index f9f5fe3526ac..b132ff94fc6f 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2324,8 +2324,6 @@ static ssize_t cgroup_file_write(struct file *file, const char __user *buf, struct cftype *cft = __d_cft(file->f_dentry); struct cgroup_subsys_state *css = cfe->css; - if (cft->write) - return cft->write(css, cft, file, buf, nbytes, ppos); if (cft->write_u64 || cft->write_s64) return cgroup_write_X64(css, cft, file, buf, nbytes, ppos); if (cft->write_string) @@ -2366,8 +2364,6 @@ static ssize_t cgroup_file_read(struct file *file, char __user *buf, struct cftype *cft = __d_cft(file->f_dentry); struct cgroup_subsys_state *css = cfe->css; - if (cft->read) - return cft->read(css, cft, file, buf, nbytes, ppos); if (cft->read_u64) return cgroup_read_u64(css, cft, file, buf, nbytes, ppos); if (cft->read_s64) @@ -2380,25 +2376,12 @@ static ssize_t cgroup_file_read(struct file *file, char __user *buf, * supports string->u64 maps, but can be extended in future. */ -static int cgroup_map_add(struct cgroup_map_cb *cb, const char *key, u64 value) -{ - struct seq_file *sf = cb->state; - return seq_printf(sf, "%s %llu\n", key, (unsigned long long)value); -} - static int cgroup_seqfile_show(struct seq_file *m, void *arg) { struct cfent *cfe = m->private; struct cftype *cft = cfe->type; struct cgroup_subsys_state *css = cfe->css; - if (cft->read_map) { - struct cgroup_map_cb cb = { - .fill = cgroup_map_add, - .state = m, - }; - return cft->read_map(css, cft, &cb); - } return cft->read_seq_string(css, cft, m); } @@ -2444,7 +2427,7 @@ static int cgroup_file_open(struct inode *inode, struct file *file) WARN_ON_ONCE(cfe->css && cfe->css != css); cfe->css = css; - if (cft->read_map || cft->read_seq_string) { + if (cft->read_seq_string) { file->f_op = &cgroup_seqfile_operations; err = single_open(file, cgroup_seqfile_show, cfe); } else if (cft->open) { @@ -2658,12 +2641,11 @@ static umode_t cgroup_file_mode(const struct cftype *cft) if (cft->mode) return cft->mode; - if (cft->read || cft->read_u64 || cft->read_s64 || - cft->read_map || cft->read_seq_string) + if (cft->read_u64 || cft->read_s64 || cft->read_seq_string) mode |= S_IRUGO; - if (cft->write || cft->write_u64 || cft->write_s64 || - cft->write_string || cft->trigger) + if (cft->write_u64 || cft->write_s64 || cft->write_string || + cft->trigger) mode |= S_IWUSR; return mode; -- cgit v1.2.3-59-g8ed1b From 7da112792753d71aed44b918395892a1fc53048a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 5 Dec 2013 12:28:04 -0500 Subject: cgroup: attach cgroup_open_file to all cgroup files In preparation of conversion to kernfs, cgroup file handling is updated so that it can be easily mapped to kernfs. This patch attaches cgroup_open_file, which used to be attached to pidlist files, to all cgroup files, introduces seq_css/cft() accessors to determine the cgroup_subsys_state and cftype associated with a given cgroup seq_file, exports them as public interface. This doesn't cause any behavior changes but unifies cgroup file handling across different file types and will help converting them to kernfs seq_show() interface. v2: Li pointed out that the original patch was using single_open_size() incorrectly assuming that the size param is private data size. Fix it by allocating @of separately and passing it to single_open() and explicitly freeing it in the release path. This isn't the prettiest but this path is gonna be restructured by the following patches pretty soon. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- include/linux/cgroup.h | 33 +++++++++++++++++++++++++++++++++ kernel/cgroup.c | 50 ++++++++++++++++++++------------------------------ 2 files changed, 53 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 53e11da6e357..c3d698a72e02 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -21,6 +21,7 @@ #include #include #include +#include #ifdef CONFIG_CGROUPS @@ -489,6 +490,26 @@ struct cftype_set { struct cftype *cfts; }; +/* + * cgroupfs file entry, pointed to from leaf dentry->d_fsdata. Don't + * access directly. + */ +struct cfent { + struct list_head node; + struct dentry *dentry; + struct cftype *type; + struct cgroup_subsys_state *css; + + /* file xattrs */ + struct simple_xattrs xattrs; +}; + +/* seq_file->private points to the following, only ->priv is public */ +struct cgroup_open_file { + struct cfent *cfe; + void *priv; +}; + /* * See the comment above CGRP_ROOT_SANE_BEHAVIOR for details. This * function can be called as long as @cgrp is accessible. @@ -504,6 +525,18 @@ static inline const char *cgroup_name(const struct cgroup *cgrp) return rcu_dereference(cgrp->name)->name; } +static inline struct cgroup_subsys_state *seq_css(struct seq_file *seq) +{ + struct cgroup_open_file *of = seq->private; + return of->cfe->css; +} + +static inline struct cftype *seq_cft(struct seq_file *seq) +{ + struct cgroup_open_file *of = seq->private; + return of->cfe->type; +} + int cgroup_add_cftypes(struct cgroup_subsys *ss, struct cftype *cfts); int cgroup_rm_cftypes(struct cftype *cfts); diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 17272893d3b8..036c05d8e572 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -130,19 +129,6 @@ static struct cgroupfs_root cgroup_dummy_root; /* dummy_top is a shorthand for the dummy hierarchy's top cgroup */ static struct cgroup * const cgroup_dummy_top = &cgroup_dummy_root.top_cgroup; -/* - * cgroupfs file entry, pointed to from leaf dentry->d_fsdata. - */ -struct cfent { - struct list_head node; - struct dentry *dentry; - struct cftype *type; - struct cgroup_subsys_state *css; - - /* file xattrs */ - struct simple_xattrs xattrs; -}; - /* The list of hierarchy roots */ static LIST_HEAD(cgroup_roots); @@ -2302,9 +2288,8 @@ out_free: static int cgroup_seqfile_show(struct seq_file *m, void *arg) { - struct cfent *cfe = m->private; - struct cftype *cft = cfe->type; - struct cgroup_subsys_state *css = cfe->css; + struct cftype *cft = seq_cft(m); + struct cgroup_subsys_state *css = seq_css(m); if (cft->read_seq_string) return cft->read_seq_string(css, cft, m); @@ -2353,10 +2338,20 @@ static int cgroup_file_open(struct inode *inode, struct file *file) WARN_ON_ONCE(cfe->css && cfe->css != css); cfe->css = css; - if (cft->open) + if (cft->open) { err = cft->open(inode, file); - else - err = single_open(file, cgroup_seqfile_show, cfe); + } else { + struct cgroup_open_file *of; + + err = -ENOMEM; + of = kzalloc(sizeof(*of), GFP_KERNEL); + if (of) { + of->cfe = cfe; + err = single_open(file, cgroup_seqfile_show, of); + if (err) + kfree(of); + } + } if (css->ss && err) css_put(css); @@ -2370,6 +2365,7 @@ static int cgroup_file_release(struct inode *inode, struct file *file) if (css->ss) css_put(css); + kfree(((struct seq_file *)file->private_data)->private); return single_release(inode, file); } @@ -3368,12 +3364,6 @@ struct cgroup_pidlist { struct delayed_work destroy_dwork; }; -/* seq_file->private points to the following */ -struct cgroup_open_file { - struct cfent *cfe; - void *priv; -}; - /* * The following two functions "fix" the issue where there are more pids * than kmalloc will give memory for; in such cases, we use vmalloc/vfree. @@ -3689,9 +3679,9 @@ static void *cgroup_pidlist_start(struct seq_file *s, loff_t *pos) * next pid to display, if any */ struct cgroup_open_file *of = s->private; - struct cgroup *cgrp = of->cfe->css->cgroup; + struct cgroup *cgrp = seq_css(s)->cgroup; struct cgroup_pidlist *l; - enum cgroup_filetype type = of->cfe->type->private; + enum cgroup_filetype type = seq_cft(s)->private; int index = 0, pid = *pos; int *iter, ret; @@ -3749,7 +3739,7 @@ static void cgroup_pidlist_stop(struct seq_file *s, void *v) if (l) mod_delayed_work(cgroup_pidlist_destroy_wq, &l->destroy_dwork, CGROUP_PIDLIST_DESTROY_DELAY); - mutex_unlock(&of->cfe->css->cgroup->pidlist_mutex); + mutex_unlock(&seq_css(s)->cgroup->pidlist_mutex); } static void *cgroup_pidlist_next(struct seq_file *s, void *v, loff_t *pos) @@ -3766,7 +3756,7 @@ static void *cgroup_pidlist_next(struct seq_file *s, void *v, loff_t *pos) if (p >= end) { return NULL; } else { - *pos = cgroup_pid_fry(of->cfe->css->cgroup, *p); + *pos = cgroup_pid_fry(seq_css(s)->cgroup, *p); return p; } } -- cgit v1.2.3-59-g8ed1b From 2da8ca822d49c8b8781800ad155aaa00e7bb5f1a Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 5 Dec 2013 12:28:04 -0500 Subject: cgroup: replace cftype->read_seq_string() with cftype->seq_show() In preparation of conversion to kernfs, cgroup file handling is updated so that it can be easily mapped to kernfs. This patch replaces cftype->read_seq_string() with cftype->seq_show() which is not limited to single_open() operation and will map directcly to kernfs seq_file interface. The conversions are mechanical. As ->seq_show() doesn't have @css and @cft, the functions which make use of them are converted to use seq_css() and seq_cft() respectively. In several occassions, e.f. if it has seq_string in its name, the function name is updated to fit the new method better. This patch does not introduce any behavior changes. Signed-off-by: Tejun Heo Acked-by: Aristeu Rozanski Acked-by: Vivek Goyal Acked-by: Michal Hocko Acked-by: Daniel Wagner Acked-by: Li Zefan Cc: Jens Axboe Cc: Ingo Molnar Cc: Peter Zijlstra Cc: Johannes Weiner Cc: Balbir Singh Cc: KAMEZAWA Hiroyuki Cc: Neil Horman --- block/blk-throttle.c | 35 ++++++------- block/cfq-iosched.c | 131 ++++++++++++++++++++-------------------------- include/linux/cgroup.h | 9 ++-- kernel/cgroup.c | 34 ++++++------ kernel/cgroup_freezer.c | 7 ++- kernel/cpuset.c | 12 ++--- kernel/sched/core.c | 7 ++- kernel/sched/cpuacct.c | 14 +++-- mm/memcontrol.c | 28 +++++----- net/core/netprio_cgroup.c | 8 +-- security/device_cgroup.c | 7 ++- 11 files changed, 128 insertions(+), 164 deletions(-) (limited to 'include/linux') diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 06534049afba..a760857e6b62 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -1303,13 +1303,10 @@ static u64 tg_prfill_cpu_rwstat(struct seq_file *sf, return __blkg_prfill_rwstat(sf, pd, &rwstat); } -static int tg_print_cpu_rwstat(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *sf) +static int tg_print_cpu_rwstat(struct seq_file *sf, void *v) { - struct blkcg *blkcg = css_to_blkcg(css); - - blkcg_print_blkgs(sf, blkcg, tg_prfill_cpu_rwstat, &blkcg_policy_throtl, - cft->private, true); + blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), tg_prfill_cpu_rwstat, + &blkcg_policy_throtl, seq_cft(sf)->private, true); return 0; } @@ -1335,19 +1332,17 @@ static u64 tg_prfill_conf_uint(struct seq_file *sf, struct blkg_policy_data *pd, return __blkg_prfill_u64(sf, pd, v); } -static int tg_print_conf_u64(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *sf) +static int tg_print_conf_u64(struct seq_file *sf, void *v) { - blkcg_print_blkgs(sf, css_to_blkcg(css), tg_prfill_conf_u64, - &blkcg_policy_throtl, cft->private, false); + blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), tg_prfill_conf_u64, + &blkcg_policy_throtl, seq_cft(sf)->private, false); return 0; } -static int tg_print_conf_uint(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *sf) +static int tg_print_conf_uint(struct seq_file *sf, void *v) { - blkcg_print_blkgs(sf, css_to_blkcg(css), tg_prfill_conf_uint, - &blkcg_policy_throtl, cft->private, false); + blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), tg_prfill_conf_uint, + &blkcg_policy_throtl, seq_cft(sf)->private, false); return 0; } @@ -1428,40 +1423,40 @@ static struct cftype throtl_files[] = { { .name = "throttle.read_bps_device", .private = offsetof(struct throtl_grp, bps[READ]), - .read_seq_string = tg_print_conf_u64, + .seq_show = tg_print_conf_u64, .write_string = tg_set_conf_u64, .max_write_len = 256, }, { .name = "throttle.write_bps_device", .private = offsetof(struct throtl_grp, bps[WRITE]), - .read_seq_string = tg_print_conf_u64, + .seq_show = tg_print_conf_u64, .write_string = tg_set_conf_u64, .max_write_len = 256, }, { .name = "throttle.read_iops_device", .private = offsetof(struct throtl_grp, iops[READ]), - .read_seq_string = tg_print_conf_uint, + .seq_show = tg_print_conf_uint, .write_string = tg_set_conf_uint, .max_write_len = 256, }, { .name = "throttle.write_iops_device", .private = offsetof(struct throtl_grp, iops[WRITE]), - .read_seq_string = tg_print_conf_uint, + .seq_show = tg_print_conf_uint, .write_string = tg_set_conf_uint, .max_write_len = 256, }, { .name = "throttle.io_service_bytes", .private = offsetof(struct tg_stats_cpu, service_bytes), - .read_seq_string = tg_print_cpu_rwstat, + .seq_show = tg_print_cpu_rwstat, }, { .name = "throttle.io_serviced", .private = offsetof(struct tg_stats_cpu, serviced), - .read_seq_string = tg_print_cpu_rwstat, + .seq_show = tg_print_cpu_rwstat, }, { } /* terminate */ }; diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 4d5cec1ad80d..744833b630c6 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -1632,11 +1632,11 @@ static u64 cfqg_prfill_weight_device(struct seq_file *sf, return __blkg_prfill_u64(sf, pd, cfqg->dev_weight); } -static int cfqg_print_weight_device(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *sf) +static int cfqg_print_weight_device(struct seq_file *sf, void *v) { - blkcg_print_blkgs(sf, css_to_blkcg(css), cfqg_prfill_weight_device, - &blkcg_policy_cfq, 0, false); + blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), + cfqg_prfill_weight_device, &blkcg_policy_cfq, + 0, false); return 0; } @@ -1650,26 +1650,23 @@ static u64 cfqg_prfill_leaf_weight_device(struct seq_file *sf, return __blkg_prfill_u64(sf, pd, cfqg->dev_leaf_weight); } -static int cfqg_print_leaf_weight_device(struct cgroup_subsys_state *css, - struct cftype *cft, - struct seq_file *sf) +static int cfqg_print_leaf_weight_device(struct seq_file *sf, void *v) { - blkcg_print_blkgs(sf, css_to_blkcg(css), cfqg_prfill_leaf_weight_device, - &blkcg_policy_cfq, 0, false); + blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), + cfqg_prfill_leaf_weight_device, &blkcg_policy_cfq, + 0, false); return 0; } -static int cfq_print_weight(struct cgroup_subsys_state *css, struct cftype *cft, - struct seq_file *sf) +static int cfq_print_weight(struct seq_file *sf, void *v) { - seq_printf(sf, "%u\n", css_to_blkcg(css)->cfq_weight); + seq_printf(sf, "%u\n", css_to_blkcg(seq_css(sf))->cfq_weight); return 0; } -static int cfq_print_leaf_weight(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *sf) +static int cfq_print_leaf_weight(struct seq_file *sf, void *v) { - seq_printf(sf, "%u\n", css_to_blkcg(css)->cfq_leaf_weight); + seq_printf(sf, "%u\n", css_to_blkcg(seq_css(sf))->cfq_leaf_weight); return 0; } @@ -1762,23 +1759,17 @@ static int cfq_set_leaf_weight(struct cgroup_subsys_state *css, return __cfq_set_weight(css, cft, val, true); } -static int cfqg_print_stat(struct cgroup_subsys_state *css, struct cftype *cft, - struct seq_file *sf) +static int cfqg_print_stat(struct seq_file *sf, void *v) { - struct blkcg *blkcg = css_to_blkcg(css); - - blkcg_print_blkgs(sf, blkcg, blkg_prfill_stat, &blkcg_policy_cfq, - cft->private, false); + blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), blkg_prfill_stat, + &blkcg_policy_cfq, seq_cft(sf)->private, false); return 0; } -static int cfqg_print_rwstat(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *sf) +static int cfqg_print_rwstat(struct seq_file *sf, void *v) { - struct blkcg *blkcg = css_to_blkcg(css); - - blkcg_print_blkgs(sf, blkcg, blkg_prfill_rwstat, &blkcg_policy_cfq, - cft->private, true); + blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), blkg_prfill_rwstat, + &blkcg_policy_cfq, seq_cft(sf)->private, true); return 0; } @@ -1798,23 +1789,19 @@ static u64 cfqg_prfill_rwstat_recursive(struct seq_file *sf, return __blkg_prfill_rwstat(sf, pd, &sum); } -static int cfqg_print_stat_recursive(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *sf) +static int cfqg_print_stat_recursive(struct seq_file *sf, void *v) { - struct blkcg *blkcg = css_to_blkcg(css); - - blkcg_print_blkgs(sf, blkcg, cfqg_prfill_stat_recursive, - &blkcg_policy_cfq, cft->private, false); + blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), + cfqg_prfill_stat_recursive, &blkcg_policy_cfq, + seq_cft(sf)->private, false); return 0; } -static int cfqg_print_rwstat_recursive(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *sf) +static int cfqg_print_rwstat_recursive(struct seq_file *sf, void *v) { - struct blkcg *blkcg = css_to_blkcg(css); - - blkcg_print_blkgs(sf, blkcg, cfqg_prfill_rwstat_recursive, - &blkcg_policy_cfq, cft->private, true); + blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), + cfqg_prfill_rwstat_recursive, &blkcg_policy_cfq, + seq_cft(sf)->private, true); return 0; } @@ -1835,13 +1822,11 @@ static u64 cfqg_prfill_avg_queue_size(struct seq_file *sf, } /* print avg_queue_size */ -static int cfqg_print_avg_queue_size(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *sf) +static int cfqg_print_avg_queue_size(struct seq_file *sf, void *v) { - struct blkcg *blkcg = css_to_blkcg(css); - - blkcg_print_blkgs(sf, blkcg, cfqg_prfill_avg_queue_size, - &blkcg_policy_cfq, 0, false); + blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), + cfqg_prfill_avg_queue_size, &blkcg_policy_cfq, + 0, false); return 0; } #endif /* CONFIG_DEBUG_BLK_CGROUP */ @@ -1851,14 +1836,14 @@ static struct cftype cfq_blkcg_files[] = { { .name = "weight_device", .flags = CFTYPE_ONLY_ON_ROOT, - .read_seq_string = cfqg_print_leaf_weight_device, + .seq_show = cfqg_print_leaf_weight_device, .write_string = cfqg_set_leaf_weight_device, .max_write_len = 256, }, { .name = "weight", .flags = CFTYPE_ONLY_ON_ROOT, - .read_seq_string = cfq_print_leaf_weight, + .seq_show = cfq_print_leaf_weight, .write_u64 = cfq_set_leaf_weight, }, @@ -1866,26 +1851,26 @@ static struct cftype cfq_blkcg_files[] = { { .name = "weight_device", .flags = CFTYPE_NOT_ON_ROOT, - .read_seq_string = cfqg_print_weight_device, + .seq_show = cfqg_print_weight_device, .write_string = cfqg_set_weight_device, .max_write_len = 256, }, { .name = "weight", .flags = CFTYPE_NOT_ON_ROOT, - .read_seq_string = cfq_print_weight, + .seq_show = cfq_print_weight, .write_u64 = cfq_set_weight, }, { .name = "leaf_weight_device", - .read_seq_string = cfqg_print_leaf_weight_device, + .seq_show = cfqg_print_leaf_weight_device, .write_string = cfqg_set_leaf_weight_device, .max_write_len = 256, }, { .name = "leaf_weight", - .read_seq_string = cfq_print_leaf_weight, + .seq_show = cfq_print_leaf_weight, .write_u64 = cfq_set_leaf_weight, }, @@ -1893,114 +1878,114 @@ static struct cftype cfq_blkcg_files[] = { { .name = "time", .private = offsetof(struct cfq_group, stats.time), - .read_seq_string = cfqg_print_stat, + .seq_show = cfqg_print_stat, }, { .name = "sectors", .private = offsetof(struct cfq_group, stats.sectors), - .read_seq_string = cfqg_print_stat, + .seq_show = cfqg_print_stat, }, { .name = "io_service_bytes", .private = offsetof(struct cfq_group, stats.service_bytes), - .read_seq_string = cfqg_print_rwstat, + .seq_show = cfqg_print_rwstat, }, { .name = "io_serviced", .private = offsetof(struct cfq_group, stats.serviced), - .read_seq_string = cfqg_print_rwstat, + .seq_show = cfqg_print_rwstat, }, { .name = "io_service_time", .private = offsetof(struct cfq_group, stats.service_time), - .read_seq_string = cfqg_print_rwstat, + .seq_show = cfqg_print_rwstat, }, { .name = "io_wait_time", .private = offsetof(struct cfq_group, stats.wait_time), - .read_seq_string = cfqg_print_rwstat, + .seq_show = cfqg_print_rwstat, }, { .name = "io_merged", .private = offsetof(struct cfq_group, stats.merged), - .read_seq_string = cfqg_print_rwstat, + .seq_show = cfqg_print_rwstat, }, { .name = "io_queued", .private = offsetof(struct cfq_group, stats.queued), - .read_seq_string = cfqg_print_rwstat, + .seq_show = cfqg_print_rwstat, }, /* the same statictics which cover the cfqg and its descendants */ { .name = "time_recursive", .private = offsetof(struct cfq_group, stats.time), - .read_seq_string = cfqg_print_stat_recursive, + .seq_show = cfqg_print_stat_recursive, }, { .name = "sectors_recursive", .private = offsetof(struct cfq_group, stats.sectors), - .read_seq_string = cfqg_print_stat_recursive, + .seq_show = cfqg_print_stat_recursive, }, { .name = "io_service_bytes_recursive", .private = offsetof(struct cfq_group, stats.service_bytes), - .read_seq_string = cfqg_print_rwstat_recursive, + .seq_show = cfqg_print_rwstat_recursive, }, { .name = "io_serviced_recursive", .private = offsetof(struct cfq_group, stats.serviced), - .read_seq_string = cfqg_print_rwstat_recursive, + .seq_show = cfqg_print_rwstat_recursive, }, { .name = "io_service_time_recursive", .private = offsetof(struct cfq_group, stats.service_time), - .read_seq_string = cfqg_print_rwstat_recursive, + .seq_show = cfqg_print_rwstat_recursive, }, { .name = "io_wait_time_recursive", .private = offsetof(struct cfq_group, stats.wait_time), - .read_seq_string = cfqg_print_rwstat_recursive, + .seq_show = cfqg_print_rwstat_recursive, }, { .name = "io_merged_recursive", .private = offsetof(struct cfq_group, stats.merged), - .read_seq_string = cfqg_print_rwstat_recursive, + .seq_show = cfqg_print_rwstat_recursive, }, { .name = "io_queued_recursive", .private = offsetof(struct cfq_group, stats.queued), - .read_seq_string = cfqg_print_rwstat_recursive, + .seq_show = cfqg_print_rwstat_recursive, }, #ifdef CONFIG_DEBUG_BLK_CGROUP { .name = "avg_queue_size", - .read_seq_string = cfqg_print_avg_queue_size, + .seq_show = cfqg_print_avg_queue_size, }, { .name = "group_wait_time", .private = offsetof(struct cfq_group, stats.group_wait_time), - .read_seq_string = cfqg_print_stat, + .seq_show = cfqg_print_stat, }, { .name = "idle_time", .private = offsetof(struct cfq_group, stats.idle_time), - .read_seq_string = cfqg_print_stat, + .seq_show = cfqg_print_stat, }, { .name = "empty_time", .private = offsetof(struct cfq_group, stats.empty_time), - .read_seq_string = cfqg_print_stat, + .seq_show = cfqg_print_stat, }, { .name = "dequeue", .private = offsetof(struct cfq_group, stats.dequeue), - .read_seq_string = cfqg_print_stat, + .seq_show = cfqg_print_stat, }, { .name = "unaccounted_time", .private = offsetof(struct cfq_group, stats.unaccounted_time), - .read_seq_string = cfqg_print_stat, + .seq_show = cfqg_print_stat, }, #endif /* CONFIG_DEBUG_BLK_CGROUP */ { } /* terminate */ diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index c3d698a72e02..b32a0f8ae9ad 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -444,12 +444,9 @@ struct cftype { * read_s64() is a signed version of read_u64() */ s64 (*read_s64)(struct cgroup_subsys_state *css, struct cftype *cft); - /* - * read_seq_string() is used for outputting a simple sequence - * using seqfile. - */ - int (*read_seq_string)(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *m); + + /* generic seq_file read interface */ + int (*seq_show)(struct seq_file *sf, void *v); /* * write_u64() is a shortcut for the common case of accepting diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 036c05d8e572..c45e63328a0a 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2212,10 +2212,9 @@ static int cgroup_release_agent_write(struct cgroup_subsys_state *css, return 0; } -static int cgroup_release_agent_show(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *seq) +static int cgroup_release_agent_show(struct seq_file *seq, void *v) { - struct cgroup *cgrp = css->cgroup; + struct cgroup *cgrp = seq_css(seq)->cgroup; if (!cgroup_lock_live_group(cgrp)) return -ENODEV; @@ -2225,10 +2224,11 @@ static int cgroup_release_agent_show(struct cgroup_subsys_state *css, return 0; } -static int cgroup_sane_behavior_show(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *seq) +static int cgroup_sane_behavior_show(struct seq_file *seq, void *v) { - seq_printf(seq, "%d\n", cgroup_sane_behavior(css->cgroup)); + struct cgroup *cgrp = seq_css(seq)->cgroup; + + seq_printf(seq, "%d\n", cgroup_sane_behavior(cgrp)); return 0; } @@ -2291,8 +2291,8 @@ static int cgroup_seqfile_show(struct seq_file *m, void *arg) struct cftype *cft = seq_cft(m); struct cgroup_subsys_state *css = seq_css(m); - if (cft->read_seq_string) - return cft->read_seq_string(css, cft, m); + if (cft->seq_show) + return cft->seq_show(m, arg); if (cft->read_u64) seq_printf(m, "%llu\n", cft->read_u64(css, cft)); @@ -2559,7 +2559,7 @@ static umode_t cgroup_file_mode(const struct cftype *cft) if (cft->mode) return cft->mode; - if (cft->read_u64 || cft->read_s64 || cft->read_seq_string) + if (cft->read_u64 || cft->read_s64 || cft->seq_show) mode |= S_IRUGO; if (cft->write_u64 || cft->write_s64 || cft->write_string || @@ -3874,7 +3874,7 @@ static struct cftype cgroup_base_files[] = { { .name = "cgroup.sane_behavior", .flags = CFTYPE_ONLY_ON_ROOT, - .read_seq_string = cgroup_sane_behavior_show, + .seq_show = cgroup_sane_behavior_show, }, /* @@ -3899,7 +3899,7 @@ static struct cftype cgroup_base_files[] = { { .name = "release_agent", .flags = CFTYPE_INSANE | CFTYPE_ONLY_ON_ROOT, - .read_seq_string = cgroup_release_agent_show, + .seq_show = cgroup_release_agent_show, .write_string = cgroup_release_agent_write, .max_write_len = PATH_MAX, }, @@ -5274,9 +5274,7 @@ static u64 current_css_set_refcount_read(struct cgroup_subsys_state *css, return count; } -static int current_css_set_cg_links_read(struct cgroup_subsys_state *css, - struct cftype *cft, - struct seq_file *seq) +static int current_css_set_cg_links_read(struct seq_file *seq, void *v) { struct cgrp_cset_link *link; struct css_set *cset; @@ -5301,9 +5299,9 @@ static int current_css_set_cg_links_read(struct cgroup_subsys_state *css, } #define MAX_TASKS_SHOWN_PER_CSS 25 -static int cgroup_css_links_read(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *seq) +static int cgroup_css_links_read(struct seq_file *seq, void *v) { + struct cgroup_subsys_state *css = seq_css(seq); struct cgrp_cset_link *link; read_lock(&css_set_lock); @@ -5349,12 +5347,12 @@ static struct cftype debug_files[] = { { .name = "current_css_set_cg_links", - .read_seq_string = current_css_set_cg_links_read, + .seq_show = current_css_set_cg_links_read, }, { .name = "cgroup_css_links", - .read_seq_string = cgroup_css_links_read, + .seq_show = cgroup_css_links_read, }, { diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index f0ff64d0ebaa..6c3154e477f6 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c @@ -301,10 +301,9 @@ out_unlock: spin_unlock_irq(&freezer->lock); } -static int freezer_read(struct cgroup_subsys_state *css, struct cftype *cft, - struct seq_file *m) +static int freezer_read(struct seq_file *m, void *v) { - struct cgroup_subsys_state *pos; + struct cgroup_subsys_state *css = seq_css(m), *pos; rcu_read_lock(); @@ -458,7 +457,7 @@ static struct cftype files[] = { { .name = "state", .flags = CFTYPE_NOT_ON_ROOT, - .read_seq_string = freezer_read, + .seq_show = freezer_read, .write_string = freezer_write, }, { diff --git a/kernel/cpuset.c b/kernel/cpuset.c index 032929f91648..4410ac6a55f1 100644 --- a/kernel/cpuset.c +++ b/kernel/cpuset.c @@ -1732,12 +1732,10 @@ out_unlock: * and since these maps can change value dynamically, one could read * gibberish by doing partial reads while a list was changing. */ -static int cpuset_common_read_seq_string(struct cgroup_subsys_state *css, - struct cftype *cft, - struct seq_file *sf) +static int cpuset_common_seq_show(struct seq_file *sf, void *v) { - struct cpuset *cs = css_cs(css); - cpuset_filetype_t type = cft->private; + struct cpuset *cs = css_cs(seq_css(sf)); + cpuset_filetype_t type = seq_cft(sf)->private; ssize_t count; char *buf, *s; int ret = 0; @@ -1824,7 +1822,7 @@ static s64 cpuset_read_s64(struct cgroup_subsys_state *css, struct cftype *cft) static struct cftype files[] = { { .name = "cpus", - .read_seq_string = cpuset_common_read_seq_string, + .seq_show = cpuset_common_seq_show, .write_string = cpuset_write_resmask, .max_write_len = (100U + 6 * NR_CPUS), .private = FILE_CPULIST, @@ -1832,7 +1830,7 @@ static struct cftype files[] = { { .name = "mems", - .read_seq_string = cpuset_common_read_seq_string, + .seq_show = cpuset_common_seq_show, .write_string = cpuset_write_resmask, .max_write_len = (100U + 6 * MAX_NUMNODES), .private = FILE_MEMLIST, diff --git a/kernel/sched/core.c b/kernel/sched/core.c index f28ec6722f0b..7e8cbb9ee4d6 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -7256,10 +7256,9 @@ static int __cfs_schedulable(struct task_group *tg, u64 period, u64 quota) return ret; } -static int cpu_stats_show(struct cgroup_subsys_state *css, struct cftype *cft, - struct seq_file *sf) +static int cpu_stats_show(struct seq_file *sf, void *v) { - struct task_group *tg = css_tg(css); + struct task_group *tg = css_tg(seq_css(sf)); struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth; seq_printf(sf, "nr_periods %d\n", cfs_b->nr_periods); @@ -7318,7 +7317,7 @@ static struct cftype cpu_files[] = { }, { .name = "stat", - .read_seq_string = cpu_stats_show, + .seq_show = cpu_stats_show, }, #endif #ifdef CONFIG_RT_GROUP_SCHED diff --git a/kernel/sched/cpuacct.c b/kernel/sched/cpuacct.c index dd88738cd4a9..622e0818f905 100644 --- a/kernel/sched/cpuacct.c +++ b/kernel/sched/cpuacct.c @@ -163,10 +163,9 @@ out: return err; } -static int cpuacct_percpu_seq_read(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *m) +static int cpuacct_percpu_seq_show(struct seq_file *m, void *V) { - struct cpuacct *ca = css_ca(css); + struct cpuacct *ca = css_ca(seq_css(m)); u64 percpu; int i; @@ -183,10 +182,9 @@ static const char * const cpuacct_stat_desc[] = { [CPUACCT_STAT_SYSTEM] = "system", }; -static int cpuacct_stats_show(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *sf) +static int cpuacct_stats_show(struct seq_file *sf, void *v) { - struct cpuacct *ca = css_ca(css); + struct cpuacct *ca = css_ca(seq_css(sf)); int cpu; s64 val = 0; @@ -220,11 +218,11 @@ static struct cftype files[] = { }, { .name = "usage_percpu", - .read_seq_string = cpuacct_percpu_seq_read, + .seq_show = cpuacct_percpu_seq_show, }, { .name = "stat", - .read_seq_string = cpuacct_stats_show, + .seq_show = cpuacct_stats_show, }, { } /* terminate */ }; diff --git a/mm/memcontrol.c b/mm/memcontrol.c index f149521a77e6..9252219376cc 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -3014,10 +3014,9 @@ static struct kmem_cache *memcg_params_to_cache(struct memcg_cache_params *p) } #ifdef CONFIG_SLABINFO -static int mem_cgroup_slabinfo_read(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *m) +static int mem_cgroup_slabinfo_read(struct seq_file *m, void *v) { - struct mem_cgroup *memcg = mem_cgroup_from_css(css); + struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); struct memcg_cache_params *params; if (!memcg_can_account_kmem(memcg)) @@ -5418,8 +5417,7 @@ static int mem_cgroup_move_charge_write(struct cgroup_subsys_state *css, #endif #ifdef CONFIG_NUMA -static int memcg_numa_stat_show(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *m) +static int memcg_numa_stat_show(struct seq_file *m, void *v) { struct numa_stat { const char *name; @@ -5435,7 +5433,7 @@ static int memcg_numa_stat_show(struct cgroup_subsys_state *css, const struct numa_stat *stat; int nid; unsigned long nr; - struct mem_cgroup *memcg = mem_cgroup_from_css(css); + struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); for (stat = stats; stat < stats + ARRAY_SIZE(stats); stat++) { nr = mem_cgroup_nr_lru_pages(memcg, stat->lru_mask); @@ -5474,10 +5472,9 @@ static inline void mem_cgroup_lru_names_not_uptodate(void) BUILD_BUG_ON(ARRAY_SIZE(mem_cgroup_lru_names) != NR_LRU_LISTS); } -static int memcg_stat_show(struct cgroup_subsys_state *css, struct cftype *cft, - struct seq_file *m) +static int memcg_stat_show(struct seq_file *m, void *v) { - struct mem_cgroup *memcg = mem_cgroup_from_css(css); + struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); struct mem_cgroup *mi; unsigned int i; @@ -5907,10 +5904,9 @@ static void mem_cgroup_oom_unregister_event(struct mem_cgroup *memcg, spin_unlock(&memcg_oom_lock); } -static int mem_cgroup_oom_control_read(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *sf) +static int mem_cgroup_oom_control_read(struct seq_file *sf, void *v) { - struct mem_cgroup *memcg = mem_cgroup_from_css(css); + struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(sf)); seq_printf(sf, "oom_kill_disable %d\n", memcg->oom_kill_disable); seq_printf(sf, "under_oom %d\n", (bool)atomic_read(&memcg->under_oom)); @@ -6260,7 +6256,7 @@ static struct cftype mem_cgroup_files[] = { }, { .name = "stat", - .read_seq_string = memcg_stat_show, + .seq_show = memcg_stat_show, }, { .name = "force_empty", @@ -6290,7 +6286,7 @@ static struct cftype mem_cgroup_files[] = { }, { .name = "oom_control", - .read_seq_string = mem_cgroup_oom_control_read, + .seq_show = mem_cgroup_oom_control_read, .write_u64 = mem_cgroup_oom_control_write, .private = MEMFILE_PRIVATE(_OOM_TYPE, OOM_CONTROL), }, @@ -6300,7 +6296,7 @@ static struct cftype mem_cgroup_files[] = { #ifdef CONFIG_NUMA { .name = "numa_stat", - .read_seq_string = memcg_numa_stat_show, + .seq_show = memcg_numa_stat_show, }, #endif #ifdef CONFIG_MEMCG_KMEM @@ -6330,7 +6326,7 @@ static struct cftype mem_cgroup_files[] = { #ifdef CONFIG_SLABINFO { .name = "kmem.slabinfo", - .read_seq_string = mem_cgroup_slabinfo_read, + .seq_show = mem_cgroup_slabinfo_read, }, #endif #endif diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c index 498710dce4a5..56cbb69ba024 100644 --- a/net/core/netprio_cgroup.c +++ b/net/core/netprio_cgroup.c @@ -173,14 +173,14 @@ static u64 read_prioidx(struct cgroup_subsys_state *css, struct cftype *cft) return css->cgroup->id; } -static int read_priomap(struct cgroup_subsys_state *css, struct cftype *cft, - struct seq_file *sf) +static int read_priomap(struct seq_file *sf, void *v) { struct net_device *dev; rcu_read_lock(); for_each_netdev_rcu(&init_net, dev) - seq_printf(sf, "%s %u\n", dev->name, netprio_prio(css, dev)); + seq_printf(sf, "%s %u\n", dev->name, + netprio_prio(seq_css(sf), dev)); rcu_read_unlock(); return 0; } @@ -238,7 +238,7 @@ static struct cftype ss_files[] = { }, { .name = "ifpriomap", - .read_seq_string = read_priomap, + .seq_show = read_priomap, .write_string = write_priomap, }, { } /* terminate */ diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 7c2a0a71049e..d3b6d2cd3a06 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c @@ -274,10 +274,9 @@ static void set_majmin(char *str, unsigned m) sprintf(str, "%u", m); } -static int devcgroup_seq_read(struct cgroup_subsys_state *css, - struct cftype *cft, struct seq_file *m) +static int devcgroup_seq_show(struct seq_file *m, void *v) { - struct dev_cgroup *devcgroup = css_to_devcgroup(css); + struct dev_cgroup *devcgroup = css_to_devcgroup(seq_css(m)); struct dev_exception_item *ex; char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN]; @@ -679,7 +678,7 @@ static struct cftype dev_cgroup_files[] = { }, { .name = "list", - .read_seq_string = devcgroup_seq_read, + .seq_show = devcgroup_seq_show, .private = DEVCG_LIST, }, { } /* terminate */ -- cgit v1.2.3-59-g8ed1b From 6612f05b88fa309c91a345690411217959bb2486 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Thu, 5 Dec 2013 12:28:04 -0500 Subject: cgroup: unify pidlist and other file handling In preparation of conversion to kernfs, cgroup file handling is updated so that it can be easily mapped to kernfs. With the previous changes, the difference between pidlist and other files are very small. Both are served by seq_file in a pretty standard way with the only difference being !pidlist files use single_open(). This patch adds cftype->seq_start(), ->seq_next and ->seq_stop() and implements the matching cgroup_seqfile_start/next/stop() which either emulates single_open() behavior or invokes cftype->seq_*() operations if specified. This allows using single seq_operations for both pidlist and other files and makes cgroup_pidlist_operations and cgorup_pidlist_open() no longer necessary. As cgroup_pidlist_open() was the only user of cftype->open(), the method is dropped together. This brings cftype file interface very close to kernfs interface and mapping shouldn't be too difficult. Once converted to kernfs, most of the plumbing code including cgroup_seqfile_*() will be removed as kernfs provides those facilities. This patch does not introduce any behavior changes. v2: Refreshed on top of the updated "cgroup: introduce struct cgroup_pidlist_open_file". v3: Refreshed on top of the updated "cgroup: attach cgroup_open_file to all cgroup files". Signed-off-by: Tejun Heo Acked-by: Li Zefan --- include/linux/cgroup.h | 6 ++- kernel/cgroup.c | 112 +++++++++++++++++++++++++++---------------------- 2 files changed, 68 insertions(+), 50 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index b32a0f8ae9ad..8b9a594f0c92 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -434,7 +434,6 @@ struct cftype { */ struct cgroup_subsys *ss; - int (*open)(struct inode *inode, struct file *file); /* * read_u64() is a shortcut for the common case of returning a * single integer. Use it in place of read() @@ -448,6 +447,11 @@ struct cftype { /* generic seq_file read interface */ int (*seq_show)(struct seq_file *sf, void *v); + /* optional ops, implement all or none */ + void *(*seq_start)(struct seq_file *sf, loff_t *ppos); + void *(*seq_next)(struct seq_file *sf, void *v, loff_t *ppos); + void (*seq_stop)(struct seq_file *sf, void *v); + /* * write_u64() is a shortcut for the common case of accepting * a single integer (as parsed by simple_strtoull) from diff --git a/kernel/cgroup.c b/kernel/cgroup.c index c45e63328a0a..f9ae38a95af2 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -2286,6 +2286,45 @@ out_free: * supports string->u64 maps, but can be extended in future. */ +static void *cgroup_seqfile_start(struct seq_file *seq, loff_t *ppos) +{ + struct cftype *cft = seq_cft(seq); + + if (cft->seq_start) { + return cft->seq_start(seq, ppos); + } else { + /* + * The same behavior and code as single_open(). Returns + * !NULL if pos is at the beginning; otherwise, NULL. + */ + return NULL + !*ppos; + } +} + +static void *cgroup_seqfile_next(struct seq_file *seq, void *v, loff_t *ppos) +{ + struct cftype *cft = seq_cft(seq); + + if (cft->seq_next) { + return cft->seq_next(seq, v, ppos); + } else { + /* + * The same behavior and code as single_open(), always + * terminate after the initial read. + */ + ++*ppos; + return NULL; + } +} + +static void cgroup_seqfile_stop(struct seq_file *seq, void *v) +{ + struct cftype *cft = seq_cft(seq); + + if (cft->seq_stop) + cft->seq_stop(seq, v); +} + static int cgroup_seqfile_show(struct seq_file *m, void *arg) { struct cftype *cft = seq_cft(m); @@ -2303,12 +2342,20 @@ static int cgroup_seqfile_show(struct seq_file *m, void *arg) return 0; } +static struct seq_operations cgroup_seq_operations = { + .start = cgroup_seqfile_start, + .next = cgroup_seqfile_next, + .stop = cgroup_seqfile_stop, + .show = cgroup_seqfile_show, +}; + static int cgroup_file_open(struct inode *inode, struct file *file) { struct cfent *cfe = __d_cfe(file->f_dentry); struct cftype *cft = __d_cft(file->f_dentry); struct cgroup *cgrp = __d_cgrp(cfe->dentry->d_parent); struct cgroup_subsys_state *css; + struct cgroup_open_file *of; int err; err = generic_file_open(inode, file); @@ -2338,24 +2385,16 @@ static int cgroup_file_open(struct inode *inode, struct file *file) WARN_ON_ONCE(cfe->css && cfe->css != css); cfe->css = css; - if (cft->open) { - err = cft->open(inode, file); - } else { - struct cgroup_open_file *of; - - err = -ENOMEM; - of = kzalloc(sizeof(*of), GFP_KERNEL); - if (of) { - of->cfe = cfe; - err = single_open(file, cgroup_seqfile_show, of); - if (err) - kfree(of); - } + of = __seq_open_private(file, &cgroup_seq_operations, + sizeof(struct cgroup_open_file)); + if (of) { + of->cfe = cfe; + return 0; } - if (css->ss && err) + if (css->ss) css_put(css); - return err; + return -ENOMEM; } static int cgroup_file_release(struct inode *inode, struct file *file) @@ -2365,8 +2404,7 @@ static int cgroup_file_release(struct inode *inode, struct file *file) if (css->ss) css_put(css); - kfree(((struct seq_file *)file->private_data)->private); - return single_release(inode, file); + return seq_release_private(inode, file); } /* @@ -3777,36 +3815,6 @@ static const struct seq_operations cgroup_pidlist_seq_operations = { .show = cgroup_pidlist_show, }; -static const struct file_operations cgroup_pidlist_operations = { - .read = seq_read, - .llseek = seq_lseek, - .write = cgroup_file_write, - .release = seq_release_private, -}; - -/* - * The following functions handle opens on a file that displays a pidlist - * (tasks or procs). Prepare an array of the process/thread IDs of whoever's - * in the cgroup. - */ -/* helper function for the two below it */ -static int cgroup_pidlist_open(struct inode *unused, struct file *file) -{ - struct cfent *cfe = __d_cfe(file->f_dentry); - struct cgroup_open_file *of; - - /* configure file information */ - file->f_op = &cgroup_pidlist_operations; - - of = __seq_open_private(file, &cgroup_pidlist_seq_operations, - sizeof(*of)); - if (!of) - return -ENOMEM; - - of->cfe = cfe; - return 0; -} - static u64 cgroup_read_notify_on_release(struct cgroup_subsys_state *css, struct cftype *cft) { @@ -3860,7 +3868,10 @@ static int cgroup_clone_children_write(struct cgroup_subsys_state *css, static struct cftype cgroup_base_files[] = { { .name = "cgroup.procs", - .open = cgroup_pidlist_open, + .seq_start = cgroup_pidlist_start, + .seq_next = cgroup_pidlist_next, + .seq_stop = cgroup_pidlist_stop, + .seq_show = cgroup_pidlist_show, .private = CGROUP_FILE_PROCS, .write_u64 = cgroup_procs_write, .mode = S_IRUGO | S_IWUSR, @@ -3885,7 +3896,10 @@ static struct cftype cgroup_base_files[] = { { .name = "tasks", .flags = CFTYPE_INSANE, /* use "procs" instead */ - .open = cgroup_pidlist_open, + .seq_start = cgroup_pidlist_start, + .seq_next = cgroup_pidlist_next, + .seq_stop = cgroup_pidlist_stop, + .seq_show = cgroup_pidlist_show, .private = CGROUP_FILE_TASKS, .write_u64 = cgroup_tasks_write, .mode = S_IRUGO | S_IWUSR, -- cgit v1.2.3-59-g8ed1b From 4b2f13a25133b115eb56771bd4a8e71a82aea968 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 06:28:48 -0800 Subject: sctp: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: Vlad Yasevich CC: Neil Horman Signed-off-by: Jeff Kirsher Signed-off-by: David S. Miller --- include/linux/sctp.h | 5 ++--- include/net/sctp/sctp.h | 5 ++--- include/net/sctp/sm.h | 5 ++--- include/net/sctp/structs.h | 5 ++--- include/net/sctp/tsnmap.h | 5 ++--- include/net/sctp/ulpevent.h | 5 ++--- include/net/sctp/ulpqueue.h | 5 ++--- include/uapi/linux/sctp.h | 5 ++--- net/sctp/associola.c | 5 ++--- net/sctp/auth.c | 5 ++--- net/sctp/bind_addr.c | 5 ++--- net/sctp/chunk.c | 5 ++--- net/sctp/command.c | 5 ++--- net/sctp/debug.c | 5 ++--- net/sctp/endpointola.c | 5 ++--- net/sctp/input.c | 5 ++--- net/sctp/inqueue.c | 5 ++--- net/sctp/ipv6.c | 5 ++--- net/sctp/objcnt.c | 5 ++--- net/sctp/output.c | 5 ++--- net/sctp/outqueue.c | 5 ++--- net/sctp/primitive.c | 5 ++--- net/sctp/proc.c | 5 ++--- net/sctp/protocol.c | 5 ++--- net/sctp/sm_make_chunk.c | 5 ++--- net/sctp/sm_sideeffect.c | 5 ++--- net/sctp/sm_statefuns.c | 5 ++--- net/sctp/sm_statetable.c | 5 ++--- net/sctp/socket.c | 5 ++--- net/sctp/ssnmap.c | 5 ++--- net/sctp/sysctl.c | 5 ++--- net/sctp/transport.c | 5 ++--- net/sctp/tsnmap.c | 5 ++--- net/sctp/ulpevent.c | 5 ++--- net/sctp/ulpqueue.c | 5 ++--- 35 files changed, 70 insertions(+), 105 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sctp.h b/include/linux/sctp.h index 3bfe8d6ee248..c4c5eba26d9f 100644 --- a/include/linux/sctp.h +++ b/include/linux/sctp.h @@ -23,9 +23,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index c5fe80697f8d..610a8c8738fa 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -21,9 +21,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 4ef75af340b6..7f4eeb340a54 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -21,9 +21,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email addresses: diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index ea0ca5f6e629..e416d6ac9c70 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -19,9 +19,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email addresses: diff --git a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h index 54bbbe547303..31b8dbaad45a 100644 --- a/include/net/sctp/tsnmap.h +++ b/include/net/sctp/tsnmap.h @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h index 27b9f5c90153..daacb32b55b5 100644 --- a/include/net/sctp/ulpevent.h +++ b/include/net/sctp/ulpevent.h @@ -25,9 +25,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/include/net/sctp/ulpqueue.h b/include/net/sctp/ulpqueue.h index b0cf5d54d717..e0dce07b8794 100644 --- a/include/net/sctp/ulpqueue.h +++ b/include/net/sctp/ulpqueue.h @@ -24,9 +24,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email addresses: diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h index ca451e99b28b..266022a2be4a 100644 --- a/include/uapi/linux/sctp.h +++ b/include/uapi/linux/sctp.h @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 68a27f9796d2..66882a26713b 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 46b5977978a1..5c9f64c1c906 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -16,9 +16,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 077bb070052b..871cdf9567e6 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c @@ -21,9 +21,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c index f2044fcb9dd1..5573e425b0c0 100644 --- a/net/sctp/chunk.c +++ b/net/sctp/chunk.c @@ -18,9 +18,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/command.c b/net/sctp/command.c index 3d9a9ff69c03..dd7375851618 100644 --- a/net/sctp/command.c +++ b/net/sctp/command.c @@ -19,9 +19,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/debug.c b/net/sctp/debug.c index e89015d8935a..95d7b15dad21 100644 --- a/net/sctp/debug.c +++ b/net/sctp/debug.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index 09b8daac87c8..6ffb6c1b13b7 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -23,9 +23,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/input.c b/net/sctp/input.c index 98b69bbecdd9..66038533ca5c 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -23,9 +23,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c index 5856932fdc38..4de12afa13d4 100644 --- a/net/sctp/inqueue.c +++ b/net/sctp/inqueue.c @@ -24,9 +24,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 7567e6f1a920..32db816ffbaa 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -21,9 +21,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/objcnt.c b/net/sctp/objcnt.c index 647396baa56f..0c28e8a55324 100644 --- a/net/sctp/objcnt.c +++ b/net/sctp/objcnt.c @@ -20,9 +20,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/output.c b/net/sctp/output.c index 0e2644d0a773..6371337e1fe7 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -20,9 +20,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index f51ba985a36e..b6b09f3f1a81 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/primitive.c b/net/sctp/primitive.c index ce1ffd811775..ab8d9f96a177 100644 --- a/net/sctp/primitive.c +++ b/net/sctp/primitive.c @@ -23,9 +23,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/proc.c b/net/sctp/proc.c index 0c0642156842..de32e14f7398 100644 --- a/net/sctp/proc.c +++ b/net/sctp/proc.c @@ -16,9 +16,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 5e17092f4ada..19bd4c5bdae9 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -23,9 +23,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index fe690320b1e4..d9aaf9641aaa 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -23,9 +23,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 1a6eef39ab2f..02b7ad1ff467 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index dfe3f36ff2aa..dd0eba919a8b 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/sm_statetable.c b/net/sctp/sm_statetable.c index c5999b2dde7d..a4f17437fb22 100644 --- a/net/sctp/sm_statetable.c +++ b/net/sctp/sm_statetable.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 72046b9729a8..191cd9257806 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -28,9 +28,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/ssnmap.c b/net/sctp/ssnmap.c index 6007124aefa0..b9c8521c1a98 100644 --- a/net/sctp/ssnmap.c +++ b/net/sctp/ssnmap.c @@ -18,9 +18,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 6b36561a1b3b..80b17b5df6bb 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -19,9 +19,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/transport.c b/net/sctp/transport.c index e332efb124cc..1d4f3ac29baf 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c @@ -24,9 +24,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c index fbda20028285..7635f9f2311d 100644 --- a/net/sctp/tsnmap.c +++ b/net/sctp/tsnmap.c @@ -21,9 +21,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 81089ed65456..85c64658bd0b 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -22,9 +22,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 1c1484ed605d..a67470083be8 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -21,9 +21,8 @@ * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, write to - * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * along with GNU CC; see the file COPYING. If not, see + * . * * Please send any bug reports or fixes you make to the * email address(es): -- cgit v1.2.3-59-g8ed1b From 4b9a445e3eeb8bd9278b1ae51c1b3a651e370cd6 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 14 Nov 2013 07:25:17 -0500 Subject: sunrpc: create a new dummy pipe for gssd to hold open rpc.gssd will naturally hold open any pipe named */clnt*/gssd that shows up under rpc_pipefs. That behavior gives us a reliable mechanism to tell whether it's actually running or not. Create a new toplevel "gssd" directory in rpc_pipefs when it's mounted. Under that directory create another directory called "clntXX", and then within that a pipe called "gssd". We'll never send an upcall along that pipe, and any downcall written to it will just return -EINVAL. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust --- include/linux/sunrpc/rpc_pipe_fs.h | 3 +- net/sunrpc/netns.h | 1 + net/sunrpc/rpc_pipe.c | 93 ++++++++++++++++++++++++++++++++++++-- net/sunrpc/sunrpc_syms.c | 8 +++- 4 files changed, 100 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index a353e0300b54..85f13424647c 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -84,7 +84,8 @@ enum { extern struct dentry *rpc_d_lookup_sb(const struct super_block *sb, const unsigned char *dir_name); -extern void rpc_pipefs_init_net(struct net *net); +extern int rpc_pipefs_init_net(struct net *net); +extern void rpc_pipefs_exit_net(struct net *net); extern struct super_block *rpc_get_sb_net(const struct net *net); extern void rpc_put_sb_net(const struct net *net); diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 779742cfc1ff..8a8e841d1547 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h @@ -14,6 +14,7 @@ struct sunrpc_net { struct cache_detail *rsi_cache; struct super_block *pipefs_sb; + struct rpc_pipe *gssd_dummy; struct mutex pipefs_sb_lock; struct list_head all_clients; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index bf04b30a788a..c23458b464c4 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -38,7 +38,7 @@ #define NET_NAME(net) ((net == &init_net) ? " (init_net)" : "") static struct file_system_type rpc_pipe_fs_type; - +static const struct rpc_pipe_ops gssd_dummy_pipe_ops; static struct kmem_cache *rpc_inode_cachep __read_mostly; @@ -1159,6 +1159,7 @@ enum { RPCAUTH_nfsd4_cb, RPCAUTH_cache, RPCAUTH_nfsd, + RPCAUTH_gssd, RPCAUTH_RootEOF }; @@ -1195,6 +1196,10 @@ static const struct rpc_filelist files[] = { .name = "nfsd", .mode = S_IFDIR | S_IRUGO | S_IXUGO, }, + [RPCAUTH_gssd] = { + .name = "gssd", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, }; /* @@ -1208,13 +1213,25 @@ struct dentry *rpc_d_lookup_sb(const struct super_block *sb, } EXPORT_SYMBOL_GPL(rpc_d_lookup_sb); -void rpc_pipefs_init_net(struct net *net) +int rpc_pipefs_init_net(struct net *net) { struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + sn->gssd_dummy = rpc_mkpipe_data(&gssd_dummy_pipe_ops, 0); + if (IS_ERR(sn->gssd_dummy)) + return PTR_ERR(sn->gssd_dummy); + mutex_init(&sn->pipefs_sb_lock); sn->gssd_running = 1; sn->pipe_version = -1; + return 0; +} + +void rpc_pipefs_exit_net(struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + + rpc_destroy_pipe_data(sn->gssd_dummy); } /* @@ -1244,11 +1261,73 @@ void rpc_put_sb_net(const struct net *net) } EXPORT_SYMBOL_GPL(rpc_put_sb_net); +static const struct rpc_filelist gssd_dummy_clnt_dir[] = { + [0] = { + .name = "clntXX", + .mode = S_IFDIR | S_IRUGO | S_IXUGO, + }, +}; + +static ssize_t +dummy_downcall(struct file *filp, const char __user *src, size_t len) +{ + return -EINVAL; +} + +static const struct rpc_pipe_ops gssd_dummy_pipe_ops = { + .upcall = rpc_pipe_generic_upcall, + .downcall = dummy_downcall, +}; + +/** + * rpc_gssd_dummy_populate - create a dummy gssd pipe + * @root: root of the rpc_pipefs filesystem + * @pipe_data: pipe data created when netns is initialized + * + * Create a dummy set of directories and a pipe that gssd can hold open to + * indicate that it is up and running. + */ +static struct dentry * +rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data) +{ + int ret = 0; + struct dentry *gssd_dentry; + struct dentry *clnt_dentry = NULL; + struct dentry *pipe_dentry = NULL; + struct qstr q = QSTR_INIT(files[RPCAUTH_gssd].name, + strlen(files[RPCAUTH_gssd].name)); + + /* We should never get this far if "gssd" doesn't exist */ + gssd_dentry = d_hash_and_lookup(root, &q); + if (!gssd_dentry) + return ERR_PTR(-ENOENT); + + ret = rpc_populate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1, NULL); + if (ret) { + pipe_dentry = ERR_PTR(ret); + goto out; + } + + q.name = gssd_dummy_clnt_dir[0].name; + q.len = strlen(gssd_dummy_clnt_dir[0].name); + clnt_dentry = d_hash_and_lookup(gssd_dentry, &q); + if (!clnt_dentry) { + pipe_dentry = ERR_PTR(-ENOENT); + goto out; + } + + pipe_dentry = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data); +out: + dput(clnt_dentry); + dput(gssd_dentry); + return pipe_dentry; +} + static int rpc_fill_super(struct super_block *sb, void *data, int silent) { struct inode *inode; - struct dentry *root; + struct dentry *root, *gssd_dentry; struct net *net = data; struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); int err; @@ -1266,6 +1345,13 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) return -ENOMEM; if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) return -ENOMEM; + + gssd_dentry = rpc_gssd_dummy_populate(root, sn->gssd_dummy); + if (IS_ERR(gssd_dentry)) { + __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF); + return PTR_ERR(gssd_dentry); + } + dprintk("RPC: sending pipefs MOUNT notification for net %p%s\n", net, NET_NAME(net)); mutex_lock(&sn->pipefs_sb_lock); @@ -1280,6 +1366,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent) return 0; err_depopulate: + dput(gssd_dentry); blocking_notifier_call_chain(&rpc_pipefs_notifier_list, RPC_PIPEFS_UMOUNT, sb); diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c index 3d6498af9adc..cd30120de9e4 100644 --- a/net/sunrpc/sunrpc_syms.c +++ b/net/sunrpc/sunrpc_syms.c @@ -44,12 +44,17 @@ static __net_init int sunrpc_init_net(struct net *net) if (err) goto err_unixgid; - rpc_pipefs_init_net(net); + err = rpc_pipefs_init_net(net); + if (err) + goto err_pipefs; + INIT_LIST_HEAD(&sn->all_clients); spin_lock_init(&sn->rpc_client_lock); spin_lock_init(&sn->rpcb_clnt_lock); return 0; +err_pipefs: + unix_gid_cache_destroy(net); err_unixgid: ip_map_cache_destroy(net); err_ipmap: @@ -60,6 +65,7 @@ err_proc: static __net_exit void sunrpc_exit_net(struct net *net) { + rpc_pipefs_exit_net(net); unix_gid_cache_destroy(net); ip_map_cache_destroy(net); rpc_proc_exit(net); -- cgit v1.2.3-59-g8ed1b From 89f842435c630f8426f414e6030bc2ffea0d6f81 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 14 Nov 2013 07:25:18 -0500 Subject: sunrpc: replace sunrpc_net->gssd_running flag with a more reliable check Now that we have a more reliable method to tell if gssd is running, we can replace the sn->gssd_running flag with a function that will query to see if it's up and running. There's also no need to attempt an upcall that we know will fail, so just return -EACCES if gssd isn't running. Finally, fix the warn_gss() message not to claim that that the upcall timed out since we don't necesarily perform one now when gssd isn't running, and remove the extraneous newline from the message. Signed-off-by: Jeff Layton Signed-off-by: Trond Myklebust --- include/linux/sunrpc/rpc_pipe_fs.h | 2 ++ net/sunrpc/auth_gss/auth_gss.c | 17 +++++++---------- net/sunrpc/netns.h | 2 -- net/sunrpc/rpc_pipe.c | 14 ++++++++++---- 4 files changed, 19 insertions(+), 16 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h index 85f13424647c..7f490bef9e99 100644 --- a/include/linux/sunrpc/rpc_pipe_fs.h +++ b/include/linux/sunrpc/rpc_pipe_fs.h @@ -131,5 +131,7 @@ extern int rpc_unlink(struct dentry *); extern int register_rpc_pipefs(void); extern void unregister_rpc_pipefs(void); +extern bool gssd_running(struct net *net); + #endif #endif diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 42fdfc634e56..0a2aee060f9f 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -536,8 +536,7 @@ static void warn_gssd(void) unsigned long now = jiffies; if (time_after(now, ratelimit)) { - printk(KERN_WARNING "RPC: AUTH_GSS upcall timed out.\n" - "Please check user daemon is running.\n"); + pr_warn("RPC: AUTH_GSS upcall failed. Please check user daemon is running.\n"); ratelimit = now + 15*HZ; } } @@ -600,7 +599,6 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) struct rpc_pipe *pipe; struct rpc_cred *cred = &gss_cred->gc_base; struct gss_upcall_msg *gss_msg; - unsigned long timeout; DEFINE_WAIT(wait); int err; @@ -608,17 +606,16 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) __func__, from_kuid(&init_user_ns, cred->cr_uid)); retry: err = 0; - /* Default timeout is 15s unless we know that gssd is not running */ - timeout = 15 * HZ; - if (!sn->gssd_running) - timeout = HZ >> 2; + /* if gssd is down, just skip upcalling altogether */ + if (!gssd_running(net)) { + warn_gssd(); + return -EACCES; + } gss_msg = gss_setup_upcall(gss_auth, cred); if (PTR_ERR(gss_msg) == -EAGAIN) { err = wait_event_interruptible_timeout(pipe_version_waitqueue, - sn->pipe_version >= 0, timeout); + sn->pipe_version >= 0, 15 * HZ); if (sn->pipe_version < 0) { - if (err == 0) - sn->gssd_running = 0; warn_gssd(); err = -EACCES; } diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 8a8e841d1547..94e506f9d72b 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h @@ -33,8 +33,6 @@ struct sunrpc_net { int pipe_version; atomic_t pipe_users; struct proc_dir_entry *use_gssp_proc; - - unsigned int gssd_running; }; extern int sunrpc_net_id; diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index c23458b464c4..5cd7ad1225a3 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c @@ -216,14 +216,11 @@ rpc_destroy_inode(struct inode *inode) static int rpc_pipe_open(struct inode *inode, struct file *filp) { - struct net *net = inode->i_sb->s_fs_info; - struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); struct rpc_pipe *pipe; int first_open; int res = -ENXIO; mutex_lock(&inode->i_mutex); - sn->gssd_running = 1; pipe = RPC_I(inode)->pipe; if (pipe == NULL) goto out; @@ -1222,7 +1219,6 @@ int rpc_pipefs_init_net(struct net *net) return PTR_ERR(sn->gssd_dummy); mutex_init(&sn->pipefs_sb_lock); - sn->gssd_running = 1; sn->pipe_version = -1; return 0; } @@ -1376,6 +1372,16 @@ err_depopulate: return err; } +bool +gssd_running(struct net *net) +{ + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct rpc_pipe *pipe = sn->gssd_dummy; + + return pipe->nreaders || pipe->nwriters; +} +EXPORT_SYMBOL_GPL(gssd_running); + static struct dentry * rpc_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) -- cgit v1.2.3-59-g8ed1b From e9fbdf176d2a7993b9d4c487b50c68d1c6019b2c Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 5 Dec 2013 14:52:13 -0800 Subject: net: phy: breakdown PHY_*_FEATURES defines Breakdown the PHY_*_FEATURES into per speed defines such that we can easily re-use them individually. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- include/linux/phy.h | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/phy.h b/include/linux/phy.h index 48a4dc3cb8cf..7ff751ae6f0a 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -27,18 +27,27 @@ #include -#define PHY_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ - SUPPORTED_10baseT_Full | \ - SUPPORTED_100baseT_Half | \ - SUPPORTED_100baseT_Full | \ - SUPPORTED_Autoneg | \ +#define PHY_DEFAULT_FEATURES (SUPPORTED_Autoneg | \ SUPPORTED_TP | \ SUPPORTED_MII) -#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \ - SUPPORTED_1000baseT_Half | \ +#define PHY_10BT_FEATURES (SUPPORTED_10baseT_Half | \ + SUPPORTED_10baseT_Full) + +#define PHY_100BT_FEATURES (SUPPORTED_100baseT_Half | \ + SUPPORTED_100baseT_Full) + +#define PHY_1000BT_FEATURES (SUPPORTED_1000baseT_Half | \ SUPPORTED_1000baseT_Full) +#define PHY_BASIC_FEATURES (PHY_10BT_FEATURES | \ + PHY_100BT_FEATURES | \ + PHY_DEFAULT_FEATURES) + +#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \ + PHY_1000BT_FEATURES) + + /* * Set phydev->irq to PHY_POLL if interrupts are not supported, * or not desired for this PHY. Set to PHY_IGNORE_INTERRUPT if -- cgit v1.2.3-59-g8ed1b From b85d20404cef6493f9d2edbafe83f9c72aece9a8 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 6 Dec 2013 15:11:57 -0500 Subject: cgroup: remove for_each_root_subsys() After the previous patch which introduced for_each_css(), for_each_root_subsys() only has two users left. This patch replaces it with for_each_subsys() + explicit subsys_mask testing and remove for_each_root_subsys() along with cgroupfs_root->subsys_list handling. This patch doesn't introduce any behavior changes. Signed-off-by: Tejun Heo Acked-by: Li Zefan --- include/linux/cgroup.h | 9 +-------- kernel/cgroup.c | 37 +++++++++++++++---------------------- 2 files changed, 16 insertions(+), 30 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 8b9a594f0c92..cfaf416492dd 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -319,9 +319,6 @@ struct cgroupfs_root { /* Unique id for this hierarchy. */ int hierarchy_id; - /* A list running through the attached subsystems */ - struct list_head subsys_list; - /* The root cgroup for this hierarchy */ struct cgroup top_cgroup; @@ -617,12 +614,8 @@ struct cgroup_subsys { #define MAX_CGROUP_TYPE_NAMELEN 32 const char *name; - /* - * Link to parent, and list entry in parent's children. - * Protected by cgroup_lock() - */ + /* link to parent, protected by cgroup_lock() */ struct cgroupfs_root *root; - struct list_head sibling; /* list of cftype_sets */ struct list_head cftsets; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 329fde82ef7c..fb1193bec4af 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -283,10 +283,6 @@ static int notify_on_release(const struct cgroup *cgrp) for ((i) = 0; (i) < CGROUP_BUILTIN_SUBSYS_COUNT && \ (((ss) = cgroup_subsys[i]) || true); (i)++) -/* iterate each subsystem attached to a hierarchy */ -#define for_each_root_subsys(root, ss) \ - list_for_each_entry((ss), &(root)->subsys_list, sibling) - /* iterate across the active hierarchies */ #define for_each_active_root(root) \ list_for_each_entry((root), &cgroup_roots, root_list) @@ -1033,7 +1029,6 @@ static int rebind_subsystems(struct cgroupfs_root *root, cgroup_css(cgroup_dummy_top, ss)); cgroup_css(cgrp, ss)->cgroup = cgrp; - list_move(&ss->sibling, &root->subsys_list); ss->root = root; if (ss->bind) ss->bind(cgroup_css(cgrp, ss)); @@ -1052,7 +1047,6 @@ static int rebind_subsystems(struct cgroupfs_root *root, RCU_INIT_POINTER(cgrp->subsys[i], NULL); cgroup_subsys[i]->root = &cgroup_dummy_root; - list_move(&ss->sibling, &cgroup_dummy_root.subsys_list); /* subsystem is now free - drop reference on module */ module_put(ss->module); @@ -1079,10 +1073,12 @@ static int cgroup_show_options(struct seq_file *seq, struct dentry *dentry) { struct cgroupfs_root *root = dentry->d_sb->s_fs_info; struct cgroup_subsys *ss; + int ssid; mutex_lock(&cgroup_root_mutex); - for_each_root_subsys(root, ss) - seq_printf(seq, ",%s", ss->name); + for_each_subsys(ss, ssid) + if (root->subsys_mask & (1 << ssid)) + seq_printf(seq, ",%s", ss->name); if (root->flags & CGRP_ROOT_SANE_BEHAVIOR) seq_puts(seq, ",sane_behavior"); if (root->flags & CGRP_ROOT_NOPREFIX) @@ -1352,7 +1348,6 @@ static void init_cgroup_root(struct cgroupfs_root *root) { struct cgroup *cgrp = &root->top_cgroup; - INIT_LIST_HEAD(&root->subsys_list); INIT_LIST_HEAD(&root->root_list); root->number_of_cgroups = 1; cgrp->root = root; @@ -4151,7 +4146,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, struct cgroup *cgrp; struct cgroup_name *name; struct cgroupfs_root *root = parent->root; - int err = 0; + int ssid, err = 0; struct cgroup_subsys *ss; struct super_block *sb = root->sb; @@ -4237,10 +4232,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, goto err_destroy; /* let's create and online css's */ - for_each_root_subsys(root, ss) { - err = create_css(cgrp, ss); - if (err) - goto err_destroy; + for_each_subsys(ss, ssid) { + if (root->subsys_mask & (1 << ssid)) { + err = create_css(cgrp, ss); + if (err) + goto err_destroy; + } } mutex_unlock(&cgroup_mutex); @@ -4536,7 +4533,6 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss) cgroup_init_cftsets(ss); /* Create the top cgroup state for this subsystem */ - list_add(&ss->sibling, &cgroup_dummy_root.subsys_list); ss->root = &cgroup_dummy_root; css = ss->css_alloc(cgroup_css(cgroup_dummy_top, ss)); /* We don't handle early failures gracefully */ @@ -4626,7 +4622,6 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss) return PTR_ERR(css); } - list_add(&ss->sibling, &cgroup_dummy_root.subsys_list); ss->root = &cgroup_dummy_root; /* our new subsystem will be attached to the dummy hierarchy. */ @@ -4702,9 +4697,6 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss) /* deassign the subsys_id */ cgroup_subsys[ss->subsys_id] = NULL; - /* remove subsystem from the dummy root's list of subsystems */ - list_del_init(&ss->sibling); - /* * disentangle the css from all css_sets attached to the dummy * top. as in loading, we need to pay our respects to the hashtable @@ -4901,11 +4893,12 @@ int proc_cgroup_show(struct seq_file *m, void *v) for_each_active_root(root) { struct cgroup_subsys *ss; struct cgroup *cgrp; - int count = 0; + int ssid, count = 0; seq_printf(m, "%d:", root->hierarchy_id); - for_each_root_subsys(root, ss) - seq_printf(m, "%s%s", count++ ? "," : "", ss->name); + for_each_subsys(ss, ssid) + if (root->subsys_mask & (1 << ssid)) + seq_printf(m, "%s%s", count++ ? "," : "", ss->name); if (strlen(root->name)) seq_printf(m, "%sname=%s", count ? "," : "", root->name); -- cgit v1.2.3-59-g8ed1b From e6247027e5173c00efb2084d688d06ff835bc3b0 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 5 Dec 2013 04:45:08 -0800 Subject: net: introduce dev_consume_skb_any() Some network drivers use dev_kfree_skb_any() and dev_kfree_skb_irq() helpers to free skbs, both for dropped packets and TX completed ones. We need to separate the two causes to get better diagnostics given by dropwatch or "perf record -e skb:kfree_skb" This patch provides two new helpers, dev_consume_skb_any() and dev_consume_skb_irq() to be used for consumed skbs. __dev_kfree_skb_irq() is slightly optimized to remove one atomic_dec_and_test() in fast path, and use this_cpu_{r|w} accessors. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 53 +++++++++++++++++++++++++++++++++++++++-------- net/core/dev.c | 45 ++++++++++++++++++++++++++-------------- 2 files changed, 74 insertions(+), 24 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7f0ed423a360..9d55e5188b96 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2368,17 +2368,52 @@ static inline int netif_copy_real_num_queues(struct net_device *to_dev, #define DEFAULT_MAX_NUM_RSS_QUEUES (8) int netif_get_num_default_rss_queues(void); -/* Use this variant when it is known for sure that it - * is executing from hardware interrupt context or with hardware interrupts - * disabled. - */ -void dev_kfree_skb_irq(struct sk_buff *skb); +enum skb_free_reason { + SKB_REASON_CONSUMED, + SKB_REASON_DROPPED, +}; + +void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason); +void __dev_kfree_skb_any(struct sk_buff *skb, enum skb_free_reason reason); -/* Use this variant in places where it could be invoked - * from either hardware interrupt or other context, with hardware interrupts - * either disabled or enabled. +/* + * It is not allowed to call kfree_skb() or consume_skb() from hardware + * interrupt context or with hardware interrupts being disabled. + * (in_irq() || irqs_disabled()) + * + * We provide four helpers that can be used in following contexts : + * + * dev_kfree_skb_irq(skb) when caller drops a packet from irq context, + * replacing kfree_skb(skb) + * + * dev_consume_skb_irq(skb) when caller consumes a packet from irq context. + * Typically used in place of consume_skb(skb) in TX completion path + * + * dev_kfree_skb_any(skb) when caller doesn't know its current irq context, + * replacing kfree_skb(skb) + * + * dev_consume_skb_any(skb) when caller doesn't know its current irq context, + * and consumed a packet. Used in place of consume_skb(skb) */ -void dev_kfree_skb_any(struct sk_buff *skb); +static inline void dev_kfree_skb_irq(struct sk_buff *skb) +{ + __dev_kfree_skb_irq(skb, SKB_REASON_DROPPED); +} + +static inline void dev_consume_skb_irq(struct sk_buff *skb) +{ + __dev_kfree_skb_irq(skb, SKB_REASON_CONSUMED); +} + +static inline void dev_kfree_skb_any(struct sk_buff *skb) +{ + __dev_kfree_skb_any(skb, SKB_REASON_DROPPED); +} + +static inline void dev_consume_skb_any(struct sk_buff *skb) +{ + __dev_kfree_skb_any(skb, SKB_REASON_CONSUMED); +} int netif_rx(struct sk_buff *skb); int netif_rx_ni(struct sk_buff *skb); diff --git a/net/core/dev.c b/net/core/dev.c index c98052487e98..6cc98dd49c7a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2145,30 +2145,42 @@ void __netif_schedule(struct Qdisc *q) } EXPORT_SYMBOL(__netif_schedule); -void dev_kfree_skb_irq(struct sk_buff *skb) +struct dev_kfree_skb_cb { + enum skb_free_reason reason; +}; + +static struct dev_kfree_skb_cb *get_kfree_skb_cb(const struct sk_buff *skb) +{ + return (struct dev_kfree_skb_cb *)skb->cb; +} + +void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason) { - if (atomic_dec_and_test(&skb->users)) { - struct softnet_data *sd; - unsigned long flags; + unsigned long flags; - local_irq_save(flags); - sd = &__get_cpu_var(softnet_data); - skb->next = sd->completion_queue; - sd->completion_queue = skb; - raise_softirq_irqoff(NET_TX_SOFTIRQ); - local_irq_restore(flags); + if (likely(atomic_read(&skb->users) == 1)) { + smp_rmb(); + atomic_set(&skb->users, 0); + } else if (likely(!atomic_dec_and_test(&skb->users))) { + return; } + get_kfree_skb_cb(skb)->reason = reason; + local_irq_save(flags); + skb->next = __this_cpu_read(softnet_data.completion_queue); + __this_cpu_write(softnet_data.completion_queue, skb); + raise_softirq_irqoff(NET_TX_SOFTIRQ); + local_irq_restore(flags); } -EXPORT_SYMBOL(dev_kfree_skb_irq); +EXPORT_SYMBOL(__dev_kfree_skb_irq); -void dev_kfree_skb_any(struct sk_buff *skb) +void __dev_kfree_skb_any(struct sk_buff *skb, enum skb_free_reason reason) { if (in_irq() || irqs_disabled()) - dev_kfree_skb_irq(skb); + __dev_kfree_skb_irq(skb, reason); else dev_kfree_skb(skb); } -EXPORT_SYMBOL(dev_kfree_skb_any); +EXPORT_SYMBOL(__dev_kfree_skb_any); /** @@ -3306,7 +3318,10 @@ static void net_tx_action(struct softirq_action *h) clist = clist->next; WARN_ON(atomic_read(&skb->users)); - trace_kfree_skb(skb, net_tx_action); + if (likely(get_kfree_skb_cb(skb)->reason == SKB_REASON_CONSUMED)) + trace_consume_skb(skb); + else + trace_kfree_skb(skb, net_tx_action); __kfree_skb(skb); } } -- cgit v1.2.3-59-g8ed1b From 317a3fa6b0814e31de5eb083bd1d047d66485d09 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 6 Dec 2013 16:13:04 +0200 Subject: ARM: OMAP1: USB: move omap_usb_config to platform data Move omap_usb_config to platform data, so that OTG driver can include it. Signed-off-by: Aaro Koskinen Acked-by: Tony Lindgren Signed-off-by: Felipe Balbi --- arch/arm/mach-omap1/include/mach/usb.h | 38 +----------------------- include/linux/platform_data/usb-omap1.h | 51 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 37 deletions(-) create mode 100644 include/linux/platform_data/usb-omap1.h (limited to 'include/linux') diff --git a/arch/arm/mach-omap1/include/mach/usb.h b/arch/arm/mach-omap1/include/mach/usb.h index 45e5ac707cbb..2c263051dc51 100644 --- a/arch/arm/mach-omap1/include/mach/usb.h +++ b/arch/arm/mach-omap1/include/mach/usb.h @@ -8,43 +8,7 @@ #define is_usb0_device(config) 0 #endif -struct omap_usb_config { - /* Configure drivers according to the connectors on your board: - * - "A" connector (rectagular) - * ... for host/OHCI use, set "register_host". - * - "B" connector (squarish) or "Mini-B" - * ... for device/gadget use, set "register_dev". - * - "Mini-AB" connector (very similar to Mini-B) - * ... for OTG use as device OR host, initialize "otg" - */ - unsigned register_host:1; - unsigned register_dev:1; - u8 otg; /* port number, 1-based: usb1 == 2 */ - - u8 hmc_mode; - - /* implicitly true if otg: host supports remote wakeup? */ - u8 rwc; - - /* signaling pins used to talk to transceiver on usbN: - * 0 == usbN unused - * 2 == usb0-only, using internal transceiver - * 3 == 3 wire bidirectional - * 4 == 4 wire bidirectional - * 6 == 6 wire unidirectional (or TLL) - */ - u8 pins[3]; - - struct platform_device *udc_device; - struct platform_device *ohci_device; - struct platform_device *otg_device; - - u32 (*usb0_init)(unsigned nwires, unsigned is_device); - u32 (*usb1_init)(unsigned nwires); - u32 (*usb2_init)(unsigned nwires, unsigned alt_pingroup); - - int (*ocpi_enable)(void); -}; +#include void omap_otg_init(struct omap_usb_config *config); diff --git a/include/linux/platform_data/usb-omap1.h b/include/linux/platform_data/usb-omap1.h new file mode 100644 index 000000000000..8c7764ddd284 --- /dev/null +++ b/include/linux/platform_data/usb-omap1.h @@ -0,0 +1,51 @@ +/* + * Platform data for OMAP1 USB + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive for + * more details. + */ +#ifndef __LINUX_USB_OMAP1_H +#define __LINUX_USB_OMAP1_H + +#include + +struct omap_usb_config { + /* Configure drivers according to the connectors on your board: + * - "A" connector (rectagular) + * ... for host/OHCI use, set "register_host". + * - "B" connector (squarish) or "Mini-B" + * ... for device/gadget use, set "register_dev". + * - "Mini-AB" connector (very similar to Mini-B) + * ... for OTG use as device OR host, initialize "otg" + */ + unsigned register_host:1; + unsigned register_dev:1; + u8 otg; /* port number, 1-based: usb1 == 2 */ + + u8 hmc_mode; + + /* implicitly true if otg: host supports remote wakeup? */ + u8 rwc; + + /* signaling pins used to talk to transceiver on usbN: + * 0 == usbN unused + * 2 == usb0-only, using internal transceiver + * 3 == 3 wire bidirectional + * 4 == 4 wire bidirectional + * 6 == 6 wire unidirectional (or TLL) + */ + u8 pins[3]; + + struct platform_device *udc_device; + struct platform_device *ohci_device; + struct platform_device *otg_device; + + u32 (*usb0_init)(unsigned nwires, unsigned is_device); + u32 (*usb1_init)(unsigned nwires); + u32 (*usb2_init)(unsigned nwires, unsigned alt_pingroup); + + int (*ocpi_enable)(void); +}; + +#endif /* __LINUX_USB_OMAP1_H */ -- cgit v1.2.3-59-g8ed1b From 339e008895a912a5049e076c9d27b29eb7ce80a7 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Fri, 6 Dec 2013 16:13:05 +0200 Subject: usb: omap1: add extcon to platform data Add extcon field to platform data. Signed-off-by: Aaro Koskinen Signed-off-by: Felipe Balbi --- include/linux/platform_data/usb-omap1.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/platform_data/usb-omap1.h b/include/linux/platform_data/usb-omap1.h index 8c7764ddd284..43b5ce139c37 100644 --- a/include/linux/platform_data/usb-omap1.h +++ b/include/linux/platform_data/usb-omap1.h @@ -23,6 +23,8 @@ struct omap_usb_config { unsigned register_dev:1; u8 otg; /* port number, 1-based: usb1 == 2 */ + const char *extcon; /* extcon device for OTG */ + u8 hmc_mode; /* implicitly true if otg: host supports remote wakeup? */ -- cgit v1.2.3-59-g8ed1b From 0d74c42f788caf3cad727c61c490d9459bc8918b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Thu, 5 Dec 2013 14:54:38 -0800 Subject: ether_addr_equal: Optimize implementation, remove unused compare_ether_addr Add a new check for CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS to reduce the number of or's used in the ether_addr_equal comparison to very slightly improve function performance. Simplify the ether_addr_equal_64bits implementation. Integrate and remove the zap_last_2bytes helper as it's now used only once. Remove the now unused compare_ether_addr function. Update the unaligned-memory-access documentation to remove the compare_ether_addr description and show how unaligned accesses could occur with ether_addr_equal. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- Documentation/unaligned-memory-access.txt | 28 +++++++++++------ include/linux/etherdevice.h | 51 +++++++++++-------------------- 2 files changed, 37 insertions(+), 42 deletions(-) (limited to 'include/linux') diff --git a/Documentation/unaligned-memory-access.txt b/Documentation/unaligned-memory-access.txt index f866c72291bf..a445da098bc6 100644 --- a/Documentation/unaligned-memory-access.txt +++ b/Documentation/unaligned-memory-access.txt @@ -137,24 +137,34 @@ Code that causes unaligned access ================================= With the above in mind, let's move onto a real life example of a function -that can cause an unaligned memory access. The following function adapted +that can cause an unaligned memory access. The following function taken from include/linux/etherdevice.h is an optimized routine to compare two ethernet MAC addresses for equality. -unsigned int compare_ether_addr(const u8 *addr1, const u8 *addr2) +bool ether_addr_equal(const u8 *addr1, const u8 *addr2) { - const u16 *a = (const u16 *) addr1; - const u16 *b = (const u16 *) addr2; +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS + u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2)) | + ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4))); + + return fold == 0; +#else + const u16 *a = (const u16 *)addr1; + const u16 *b = (const u16 *)addr2; return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; +#endif } -In the above function, the reference to a[0] causes 2 bytes (16 bits) to -be read from memory starting at address addr1. Think about what would happen -if addr1 was an odd address such as 0x10003. (Hint: it'd be an unaligned -access.) +In the above function, when the hardware has efficient unaligned access +capability, there is no issue with this code. But when the hardware isn't +able to access memory on arbitrary boundaries, the reference to a[0] causes +2 bytes (16 bits) to be read from memory starting at address addr1. + +Think about what would happen if addr1 was an odd address such as 0x10003. +(Hint: it'd be an unaligned access.) Despite the potential unaligned access problems with the above function, it -is included in the kernel anyway but is understood to only work on +is included in the kernel anyway but is understood to only work normally on 16-bit-aligned addresses. It is up to the caller to ensure this alignment or not use this function at all. This alignment-unsafe function is still useful as it is a decent optimization for the cases when you can ensure alignment, diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index fc4a9aa7dd82..3526e819d7ae 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef __KERNEL__ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); @@ -210,41 +211,27 @@ static inline void eth_hw_addr_inherit(struct net_device *dst, memcpy(dst->dev_addr, src->dev_addr, ETH_ALEN); } -/** - * compare_ether_addr - Compare two Ethernet addresses - * @addr1: Pointer to a six-byte array containing the Ethernet address - * @addr2: Pointer other six-byte array containing the Ethernet address - * - * Compare two Ethernet addresses, returns 0 if equal, non-zero otherwise. - * Unlike memcmp(), it doesn't return a value suitable for sorting. - */ -static inline unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2) -{ - const u16 *a = (const u16 *) addr1; - const u16 *b = (const u16 *) addr2; - - BUILD_BUG_ON(ETH_ALEN != 6); - return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; -} - /** * ether_addr_equal - Compare two Ethernet addresses * @addr1: Pointer to a six-byte array containing the Ethernet address * @addr2: Pointer other six-byte array containing the Ethernet address * * Compare two Ethernet addresses, returns true if equal + * + * Please note: addr1 & addr2 must both be aligned to u16. */ static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2) { - return !compare_ether_addr(addr1, addr2); -} +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2)) | + ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4))); -static inline unsigned long zap_last_2bytes(unsigned long value) -{ -#ifdef __BIG_ENDIAN - return value >> 16; + return fold == 0; #else - return value << 16; + const u16 *a = (const u16 *)addr1; + const u16 *b = (const u16 *)addr2; + + return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0; #endif } @@ -265,16 +252,14 @@ static inline unsigned long zap_last_2bytes(unsigned long value) static inline bool ether_addr_equal_64bits(const u8 addr1[6+2], const u8 addr2[6+2]) { -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - unsigned long fold = ((*(unsigned long *)addr1) ^ - (*(unsigned long *)addr2)); - - if (sizeof(fold) == 8) - return zap_last_2bytes(fold) == 0; +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 + u64 fold = (*(const u64 *)addr1) ^ (*(const u64 *)addr2); - fold |= zap_last_2bytes((*(unsigned long *)(addr1 + 4)) ^ - (*(unsigned long *)(addr2 + 4))); - return fold == 0; +#ifdef __BIG_ENDIAN + return (fold >> 16) == 0; +#else + return (fold << 16) == 0; +#endif #else return ether_addr_equal(addr1, addr2); #endif -- cgit v1.2.3-59-g8ed1b From 8b48463f89429af408ff695244dc627e1acff4f7 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 3 Dec 2013 08:49:16 +0800 Subject: ACPI: Clean up inclusions of ACPI header files Replace direct inclusions of , and , which are incorrect, with inclusions and remove some inclusions of those files that aren't necessary. First of all, , and should not be included directly from any files that are built for CONFIG_ACPI unset, because that generally leads to build warnings about undefined symbols in !CONFIG_ACPI builds. For CONFIG_ACPI set, includes those files and for CONFIG_ACPI unset it provides stub ACPI symbols to be used in that case. Second, there are ordering dependencies between those files that always have to be met. Namely, it is required that be included prior to so that the acpi_pci_root declarations the latter depends on are always there. And which provides basic ACPICA type declarations should always be included prior to any other ACPI headers in CONFIG_ACPI builds. That also is taken care of including as appropriate. Signed-off-by: Lv Zheng Cc: Greg Kroah-Hartman Cc: Matthew Garrett Cc: Tony Luck Cc: "H. Peter Anvin" Acked-by: Bjorn Helgaas (drivers/pci stuff) Acked-by: Konrad Rzeszutek Wilk (Xen stuff) Signed-off-by: Rafael J. Wysocki --- arch/ia64/hp/common/aml_nfw.c | 3 +-- arch/x86/kernel/apic/apic_flat_64.c | 4 +--- arch/x86/kernel/apic/io_apic.c | 3 --- arch/x86/pci/mmconfig_32.c | 1 - arch/x86/platform/olpc/olpc-xo15-sci.c | 3 +-- drivers/acpi/ac.c | 3 +-- drivers/acpi/acpi_extlog.c | 1 - drivers/acpi/acpi_pad.c | 3 +-- drivers/acpi/apei/einj.c | 1 - drivers/acpi/battery.c | 3 +-- drivers/acpi/blacklist.c | 1 - drivers/acpi/bus.c | 2 -- drivers/acpi/button.c | 3 +-- drivers/acpi/custom_method.c | 2 +- drivers/acpi/debugfs.c | 2 +- drivers/acpi/dock.c | 2 -- drivers/acpi/ec.c | 5 ++--- drivers/acpi/event.c | 2 +- drivers/acpi/fan.c | 3 +-- drivers/acpi/hed.c | 2 -- drivers/acpi/numa.c | 1 - drivers/acpi/osl.c | 3 --- drivers/acpi/pci_irq.c | 2 -- drivers/acpi/pci_link.c | 4 +--- drivers/acpi/pci_root.c | 4 +--- drivers/acpi/power.c | 3 +-- drivers/acpi/proc.c | 4 +--- drivers/acpi/processor_core.c | 3 +-- drivers/acpi/processor_idle.c | 4 +--- drivers/acpi/processor_perflib.c | 7 ++----- drivers/acpi/processor_thermal.c | 7 ++----- drivers/acpi/processor_throttling.c | 7 ++----- drivers/acpi/sbshc.c | 3 +-- drivers/acpi/scan.c | 2 -- drivers/acpi/sleep.c | 4 ---- drivers/acpi/sysfs.c | 2 +- drivers/acpi/thermal.c | 5 ++--- drivers/acpi/utils.c | 2 -- drivers/acpi/video.c | 5 ++--- drivers/acpi/wakeup.c | 1 - drivers/ata/libata-acpi.c | 2 -- drivers/ata/pata_acpi.c | 5 ++--- drivers/char/hpet.c | 7 ++----- drivers/char/tpm/tpm_acpi.c | 2 +- drivers/char/tpm/tpm_ppi.c | 1 - drivers/gpu/drm/i915/intel_acpi.c | 2 -- drivers/gpu/drm/nouveau/nouveau_acpi.c | 7 +------ drivers/gpu/drm/radeon/radeon_acpi.c | 6 +----- drivers/hv/vmbus_drv.c | 2 -- drivers/hwmon/acpi_power_meter.c | 3 +-- drivers/hwmon/asus_atk0110.c | 7 +------ drivers/ide/ide-acpi.c | 1 - drivers/input/misc/atlas_btns.c | 2 +- drivers/iommu/amd_iommu_init.c | 1 - drivers/iommu/intel_irq_remapping.c | 4 ++-- drivers/pci/hotplug/acpiphp_ibm.c | 3 +-- drivers/pci/hotplug/pciehp.h | 2 -- drivers/pci/ioapic.c | 1 - drivers/pci/pci-acpi.c | 3 --- drivers/pci/pci-label.c | 1 - drivers/platform/x86/acer-wmi.c | 2 -- drivers/platform/x86/asus-laptop.c | 3 +-- drivers/platform/x86/asus-wmi.c | 3 +-- drivers/platform/x86/classmate-laptop.c | 3 +-- drivers/platform/x86/dell-wmi-aio.c | 1 - drivers/platform/x86/dell-wmi.c | 1 - drivers/platform/x86/eeepc-laptop.c | 3 +-- drivers/platform/x86/eeepc-wmi.c | 2 +- drivers/platform/x86/hp_accel.c | 2 +- drivers/platform/x86/ideapad-laptop.c | 3 +-- drivers/platform/x86/intel-rst.c | 2 +- drivers/platform/x86/intel-smartconnect.c | 2 +- drivers/platform/x86/intel_menlow.c | 4 +--- drivers/platform/x86/intel_oaktrail.c | 3 --- drivers/platform/x86/mxm-wmi.c | 3 +-- drivers/platform/x86/panasonic-laptop.c | 4 +--- drivers/platform/x86/pvpanic.c | 3 +-- drivers/platform/x86/samsung-q10.c | 2 +- drivers/platform/x86/sony-laptop.c | 4 +--- drivers/platform/x86/tc1100-wmi.c | 4 +--- drivers/platform/x86/thinkpad_acpi.c | 14 ++++---------- drivers/platform/x86/toshiba_acpi.c | 4 +--- drivers/platform/x86/toshiba_bluetooth.c | 4 +--- drivers/platform/x86/wmi.c | 2 -- drivers/platform/x86/xo15-ebook.c | 3 +-- drivers/pnp/pnpacpi/core.c | 1 - drivers/pnp/pnpacpi/pnpacpi.h | 1 - drivers/sfi/sfi_acpi.c | 2 +- drivers/staging/quickstart/quickstart.c | 2 +- drivers/usb/core/usb-acpi.c | 1 - drivers/xen/xen-acpi-cpuhotplug.c | 3 --- drivers/xen/xen-acpi-memhotplug.c | 1 - drivers/xen/xen-acpi-pad.c | 5 ++--- drivers/xen/xen-acpi-processor.c | 4 +--- include/acpi/acpi_bus.h | 2 -- include/acpi/acpi_drivers.h | 3 --- include/linux/acpi_io.h | 2 +- include/linux/ide.h | 8 ++------ include/linux/iscsi_ibft.h | 2 +- include/linux/pci_hotplug.h | 3 +-- include/linux/sfi_acpi.h | 2 +- include/linux/tboot.h | 2 +- tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c | 5 +---- 103 files changed, 80 insertions(+), 234 deletions(-) (limited to 'include/linux') diff --git a/arch/ia64/hp/common/aml_nfw.c b/arch/ia64/hp/common/aml_nfw.c index 916ffe770bcf..84715fcbba08 100644 --- a/arch/ia64/hp/common/aml_nfw.c +++ b/arch/ia64/hp/common/aml_nfw.c @@ -23,8 +23,7 @@ */ #include -#include -#include +#include #include MODULE_AUTHOR("Bjorn Helgaas "); diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c index 00c77cf78e9e..ccbf857d1d55 100644 --- a/arch/x86/kernel/apic/apic_flat_64.c +++ b/arch/x86/kernel/apic/apic_flat_64.c @@ -21,9 +21,7 @@ #include #include -#ifdef CONFIG_ACPI -#include -#endif +#include static struct apic apic_physflat; static struct apic apic_flat; diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index e63a5bd2a78f..4d67a7531d45 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -37,9 +37,6 @@ #include #include /* time_after() */ #include -#ifdef CONFIG_ACPI -#include -#endif #include #include #include diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c index 5c90975cdf0f..43984bc1665a 100644 --- a/arch/x86/pci/mmconfig_32.c +++ b/arch/x86/pci/mmconfig_32.c @@ -14,7 +14,6 @@ #include #include #include -#include /* Assume systems with more busses have correct MCFG */ #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) diff --git a/arch/x86/platform/olpc/olpc-xo15-sci.c b/arch/x86/platform/olpc/olpc-xo15-sci.c index 649a12befba9..08e350e757dc 100644 --- a/arch/x86/platform/olpc/olpc-xo15-sci.c +++ b/arch/x86/platform/olpc/olpc-xo15-sci.c @@ -15,8 +15,7 @@ #include #include -#include -#include +#include #include #define DRV_NAME "olpc-xo15-sci" diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 8711e3797165..8095943e6e11 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -32,8 +32,7 @@ #include #include #include -#include -#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index a6869e110ce5..2635a01c5b3e 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index fc6008fbce35..65610c0e7243 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -28,8 +28,7 @@ #include #include #include -#include -#include +#include #include #define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad" diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index fb57d03e698b..ca0c6d7ec0d4 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -33,7 +33,6 @@ #include #include #include -#include #include "apei-internal.h" diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index fbf1aceda8b8..e90ef8b96f26 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -36,8 +36,7 @@ #include #include -#include -#include +#include #include #define PREFIX "ACPI: " diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 078c4f7fe2dd..05ee8f61bfb5 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include "internal.h" diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index bba9b72e25f8..cfea1c58f034 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -37,8 +37,6 @@ #include #endif #include -#include -#include #include #include #include diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index c971929d75c2..9e3a6cb99f90 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -31,8 +31,7 @@ #include #include #include -#include -#include +#include #include #define PREFIX "ACPI: " diff --git a/drivers/acpi/custom_method.c b/drivers/acpi/custom_method.c index 12b62f2cdb3f..c68e72414a67 100644 --- a/drivers/acpi/custom_method.c +++ b/drivers/acpi/custom_method.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include "internal.h" diff --git a/drivers/acpi/debugfs.c b/drivers/acpi/debugfs.c index b55d6a20dc0e..6b1919f6bd82 100644 --- a/drivers/acpi/debugfs.c +++ b/drivers/acpi/debugfs.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include #define _COMPONENT ACPI_SYSTEM_COMPONENT ACPI_MODULE_NAME("debugfs"); diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index dcd73ccb514c..9ab9e783a894 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -32,8 +32,6 @@ #include #include #include -#include -#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index ba5b56db9d27..ff40120e930e 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -39,10 +39,9 @@ #include #include #include -#include -#include -#include +#include #include +#include #include "internal.h" diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c index cae3b387b867..ef2d730734dc 100644 --- a/drivers/acpi/event.c +++ b/drivers/acpi/event.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index ba3da88cee45..1fb62900f32a 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -29,8 +29,7 @@ #include #include #include -#include -#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c index 13b1d39d7cdf..aafe3ca829c2 100644 --- a/drivers/acpi/hed.c +++ b/drivers/acpi/hed.c @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include static struct acpi_device_id acpi_hed_ids[] = { diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index a2343a1d9e0b..9e6816ef280a 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -29,7 +29,6 @@ #include #include #include -#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 54a20ff4b864..244be2affea7 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -49,9 +49,6 @@ #include #include -#include -#include -#include #include "internal.h" #define _COMPONENT ACPI_OS_SERVICES diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 41c5e1b799ef..52d45ea2bc4f 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -37,8 +37,6 @@ #include #include #include -#include -#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index 2652a614deeb..ea6b8d16dcc8 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -39,9 +39,7 @@ #include #include #include - -#include -#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 0703bff5e60e..cd20f3486cfa 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -35,9 +35,7 @@ #include #include #include -#include -#include -#include +#include /* for acpi_hest_init() */ #include "internal.h" diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index c2ad391d8041..ad7da686e6e6 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -42,8 +42,7 @@ #include #include #include -#include -#include +#include #include "sleep.h" #include "internal.h" diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index 6a5b152ad4d0..db061bfd95a8 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -3,11 +3,9 @@ #include #include #include +#include #include -#include -#include - #include "sleep.h" #define _COMPONENT ACPI_SYSTEM_COMPONENT diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index b3171f30b319..34e7b3c6a08d 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -10,8 +10,7 @@ #include #include #include - -#include +#include #include #include "internal.h" diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 644516d9bde6..d2d44e0190a3 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -35,6 +35,7 @@ #include #include #include +#include /* * Include the apic definitions for x86 to have the APIC timer related defines @@ -46,9 +47,6 @@ #include #endif -#include -#include - #define PREFIX "ACPI: " #define ACPI_PROCESSOR_CLASS "processor" diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 60a7c28fc167..ff90054f04fd 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -31,15 +31,12 @@ #include #include #include - +#include +#include #ifdef CONFIG_X86 #include #endif -#include -#include -#include - #define PREFIX "ACPI: " #define ACPI_PROCESSOR_CLASS "processor" diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index d1d2e7fb5b30..f95e7584d6e6 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -30,12 +30,9 @@ #include #include #include - -#include - -#include +#include #include -#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index e7dd2c1fee79..28baa05b8018 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -32,14 +32,11 @@ #include #include #include - +#include +#include #include #include -#include -#include -#include - #define PREFIX "ACPI: " #define ACPI_PROCESSOR_CLASS "processor" diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c index b78bc605837e..26e5b5060523 100644 --- a/drivers/acpi/sbshc.c +++ b/drivers/acpi/sbshc.c @@ -8,8 +8,7 @@ * the Free Software Foundation version 2. */ -#include -#include +#include #include #include #include diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 15daa21fcd05..56421a921a2b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -12,8 +12,6 @@ #include #include -#include - #include "internal.h" #define _COMPONENT ACPI_BUS_COMPONENT diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 14df30580e15..ea9cc373ffd8 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -18,12 +18,8 @@ #include #include #include - #include -#include -#include - #include "internal.h" #include "sleep.h" diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index db5293650f62..ba07d9a927ab 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include "internal.h" diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 0d9f46b5ae6d..1fd21ad69c98 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -41,10 +41,9 @@ #include #include #include -#include #include -#include -#include +#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 6d408bfbbb1d..1336b9151479 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -30,8 +30,6 @@ #include #include #include -#include -#include #include "internal.h" diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 995e91bcb97b..b727d105046d 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -37,12 +37,11 @@ #include #include #include -#include #include -#include -#include #include +#include #include +#include #include "internal.h" diff --git a/drivers/acpi/wakeup.c b/drivers/acpi/wakeup.c index 7bfbe40bc43b..1638401ab282 100644 --- a/drivers/acpi/wakeup.c +++ b/drivers/acpi/wakeup.c @@ -5,7 +5,6 @@ #include #include -#include #include #include diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 4372cfa883c9..8e22d9762328 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -20,8 +20,6 @@ #include #include "libata.h" -#include - unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT; module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644); MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM, 0x8=FPDMA non-zero offset, 0x10=FPDMA DMA Setup FIS auto-activate)"); diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c index 73212c9c6d5b..62c9ac80c6e9 100644 --- a/drivers/ata/pata_acpi.c +++ b/drivers/ata/pata_acpi.c @@ -12,11 +12,10 @@ #include #include #include -#include -#include - +#include #include #include +#include #define DRV_NAME "pata_acpi" #define DRV_VERSION "0.2.3" diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 5d9c31dfc905..d5d4cd82b9f7 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -34,15 +34,12 @@ #include #include #include - +#include +#include #include #include #include -#include -#include -#include - /* * The High Precision Event Timer driver. * This driver is closely modelled after the rtc.c driver. diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c index 64420b3396a2..b9a57fa4b710 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_acpi.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include "tpm.h" #include "tpm_eventlog.h" diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index 8e562dc65601..dd60ef336f8d 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -1,5 +1,4 @@ #include -#include #include "tpm.h" static const u8 tpm_ppi_uuid[] = { diff --git a/drivers/gpu/drm/i915/intel_acpi.c b/drivers/gpu/drm/i915/intel_acpi.c index dfff0907f70e..5325b25ccbb4 100644 --- a/drivers/gpu/drm/i915/intel_acpi.c +++ b/drivers/gpu/drm/i915/intel_acpi.c @@ -6,8 +6,6 @@ #include #include #include -#include - #include #include "i915_drv.h" diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 95c740454049..1f0b6d238cfa 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -1,15 +1,10 @@ #include #include #include -#include -#include -#include -#include #include - #include - #include +#include #include "nouveau_drm.h" #include "nouveau_acpi.h" diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c index 98a9074b306b..77e9d07c55b6 100644 --- a/drivers/gpu/drm/radeon/radeon_acpi.c +++ b/drivers/gpu/drm/radeon/radeon_acpi.c @@ -25,18 +25,14 @@ #include #include #include -#include -#include +#include #include - #include #include #include "radeon.h" #include "radeon_acpi.h" #include "atom.h" -#include - #define ACPI_AC_CLASS "ac_adapter" extern void radeon_pm_acpi_event_handler(struct radeon_device *rdev); diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index 48aad4faea06..077bb1bdac34 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -39,7 +38,6 @@ #include #include "hyperv_vmbus.h" - static struct acpi_device *hv_acpi_dev; static struct tasklet_struct msg_dpc; diff --git a/drivers/hwmon/acpi_power_meter.c b/drivers/hwmon/acpi_power_meter.c index 6a34f7f48eb9..579bdf93be43 100644 --- a/drivers/hwmon/acpi_power_meter.c +++ b/drivers/hwmon/acpi_power_meter.c @@ -30,8 +30,7 @@ #include #include #include -#include -#include +#include #define ACPI_POWER_METER_NAME "power_meter" ACPI_MODULE_NAME(ACPI_POWER_METER_NAME); diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c index 1d7ff46812c3..ae208f612198 100644 --- a/drivers/hwmon/asus_atk0110.c +++ b/drivers/hwmon/asus_atk0110.c @@ -16,12 +16,7 @@ #include #include #include - -#include -#include -#include -#include - +#include #define ATK_HID "ATK0110" diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index d9e1f7ccfe6f..333d4053e727 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c index 5d4402365a52..d781b5e52065 100644 --- a/drivers/input/misc/atlas_btns.c +++ b/drivers/input/misc/atlas_btns.c @@ -28,8 +28,8 @@ #include #include #include +#include #include -#include #define ACPI_ATLAS_NAME "Atlas ACPI" #define ACPI_ATLAS_CLASS "Atlas" diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 8f798be6e398..28b4bea7c109 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c index bab10b1002fb..0cb7528b30a1 100644 --- a/drivers/iommu/intel_irq_remapping.c +++ b/drivers/iommu/intel_irq_remapping.c @@ -6,11 +6,11 @@ #include #include #include +#include +#include #include #include #include -#include -#include #include #include #include diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index ecfac7e72d91..8dcccffd6e21 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -31,12 +31,11 @@ #include #include #include -#include #include #include -#include #include #include +#include #include "acpiphp.h" #include "../pci.h" diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h index 21e865ded1dc..24e147cae667 100644 --- a/drivers/pci/hotplug/pciehp.h +++ b/drivers/pci/hotplug/pciehp.h @@ -163,8 +163,6 @@ static inline const char *slot_name(struct slot *slot) } #ifdef CONFIG_ACPI -#include -#include #include void __init pciehp_acpi_slot_detection_init(void); diff --git a/drivers/pci/ioapic.c b/drivers/pci/ioapic.c index 50ce68098298..2122b2bf006f 100644 --- a/drivers/pci/ioapic.c +++ b/drivers/pci/ioapic.c @@ -20,7 +20,6 @@ #include #include #include -#include struct ioapic { acpi_handle handle; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 577074efbe62..43e317991326 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -12,9 +12,6 @@ #include #include #include -#include -#include - #include #include #include diff --git a/drivers/pci/pci-label.c b/drivers/pci/pci-label.c index d51f45aa669e..dbafcc8ef673 100644 --- a/drivers/pci/pci-label.c +++ b/drivers/pci/pci-label.c @@ -29,7 +29,6 @@ #include #include #include -#include #include "pci.h" #define DEVICE_LABEL_DSM 0x07 diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index c9076bdaf2c1..c91f69b39db4 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -41,8 +41,6 @@ #include #include #include - -#include #include MODULE_AUTHOR("Carlos Corbacho"); diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 0e9c169b42f8..430b5c3c46b4 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -53,8 +53,7 @@ #include #include #include -#include -#include +#include #define ASUS_LAPTOP_VERSION "0.42" diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 19c313b056c3..df7ecb9ecd9d 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -45,8 +45,7 @@ #include #include #include -#include -#include +#include #include #include "asus-wmi.h" diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c index 6dfa8d3b4eec..70d355a9ae2c 100644 --- a/drivers/platform/x86/classmate-laptop.c +++ b/drivers/platform/x86/classmate-laptop.c @@ -21,14 +21,13 @@ #include #include #include -#include +#include #include #include #include MODULE_LICENSE("GPL"); - struct cmpc_accel { int sensitivity; int g_select; diff --git a/drivers/platform/x86/dell-wmi-aio.c b/drivers/platform/x86/dell-wmi-aio.c index bcf8cc6b5537..dbc97a33bbc8 100644 --- a/drivers/platform/x86/dell-wmi-aio.c +++ b/drivers/platform/x86/dell-wmi-aio.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index fa9a2171cc13..bdf483babb43 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index aefcc32e5634..cabd56700cae 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c @@ -28,8 +28,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c index af67e6e56ebb..6112933f6278 100644 --- a/drivers/platform/x86/eeepc-wmi.c +++ b/drivers/platform/x86/eeepc-wmi.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include "asus-wmi.h" diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c index a8e43cf70fac..aff4d0670edf 100644 --- a/drivers/platform/x86/hp_accel.c +++ b/drivers/platform/x86/hp_accel.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include "../../misc/lis3lv02d/lis3lv02d.h" #define DRIVER_NAME "hp_accel" diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 6788acc22ab9..70b57295d0a0 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -26,8 +26,7 @@ #include #include #include -#include -#include +#include #include #include #include diff --git a/drivers/platform/x86/intel-rst.c b/drivers/platform/x86/intel-rst.c index a2083a9e5662..d45bca34bf1b 100644 --- a/drivers/platform/x86/intel-rst.c +++ b/drivers/platform/x86/intel-rst.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel-smartconnect.c b/drivers/platform/x86/intel-smartconnect.c index 1838400dc036..04cf5dffdfd9 100644 --- a/drivers/platform/x86/intel-smartconnect.c +++ b/drivers/platform/x86/intel-smartconnect.c @@ -19,7 +19,7 @@ #include #include -#include +#include MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c index 11244f8703c4..e8b46d2c468c 100644 --- a/drivers/platform/x86/intel_menlow.c +++ b/drivers/platform/x86/intel_menlow.c @@ -36,10 +36,8 @@ #include #include #include - #include -#include -#include +#include MODULE_AUTHOR("Thomas Sujith"); MODULE_AUTHOR("Zhang Rui"); diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c index f6f18cde0f11..4bc960416785 100644 --- a/drivers/platform/x86/intel_oaktrail.c +++ b/drivers/platform/x86/intel_oaktrail.c @@ -50,9 +50,6 @@ #include #include #include -#include -#include - #define DRIVER_NAME "intel_oaktrail" #define DRIVER_VERSION "0.4ac1" diff --git a/drivers/platform/x86/mxm-wmi.c b/drivers/platform/x86/mxm-wmi.c index 0aea63b3729a..3c59c0a3ee0f 100644 --- a/drivers/platform/x86/mxm-wmi.c +++ b/drivers/platform/x86/mxm-wmi.c @@ -20,8 +20,7 @@ #include #include #include -#include -#include +#include MODULE_AUTHOR("Dave Airlie"); MODULE_DESCRIPTION("MXM WMI Driver"); diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 10d12b221601..137d602395e8 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -125,12 +125,10 @@ #include #include #include -#include -#include +#include #include #include - #ifndef ACPI_HOTKEY_COMPONENT #define ACPI_HOTKEY_COMPONENT 0x10000000 #endif diff --git a/drivers/platform/x86/pvpanic.c b/drivers/platform/x86/pvpanic.c index 47ae0c47d4b5..c9f6e511daa6 100644 --- a/drivers/platform/x86/pvpanic.c +++ b/drivers/platform/x86/pvpanic.c @@ -24,8 +24,7 @@ #include #include #include -#include -#include +#include MODULE_AUTHOR("Hu Tao "); MODULE_DESCRIPTION("pvpanic device driver"); diff --git a/drivers/platform/x86/samsung-q10.c b/drivers/platform/x86/samsung-q10.c index cae7098e9b0d..5413f62d2e61 100644 --- a/drivers/platform/x86/samsung-q10.c +++ b/drivers/platform/x86/samsung-q10.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #define SAMSUNGQ10_BL_MAX_INTENSITY 7 diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 47caab0ea7a1..1d00039de72a 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -61,9 +61,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -71,6 +68,7 @@ #include #include #endif +#include #define dprintk(fmt, ...) \ do { \ diff --git a/drivers/platform/x86/tc1100-wmi.c b/drivers/platform/x86/tc1100-wmi.c index 9b93fdb61ed7..6a6ea28a7e51 100644 --- a/drivers/platform/x86/tc1100-wmi.c +++ b/drivers/platform/x86/tc1100-wmi.c @@ -32,9 +32,7 @@ #include #include #include -#include -#include -#include +#include #include #define GUID "C364AC71-36DB-495A-8494-B439D472A505" diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 05e046aa5e31..9d7e34b0109c 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -61,7 +61,6 @@ #include #include #include - #include #include #include @@ -74,21 +73,16 @@ #include #include #include -#include - #include #include #include - +#include +#include +#include #include #include #include - -#include - -#include - -#include +#include /* ThinkPad CMOS commands */ #define TP_CMOS_VOLUME_DOWN 0 diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 0cfadb65f7c6..b5f17eb7ad2e 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -54,11 +54,9 @@ #include #include #include - +#include #include -#include - MODULE_AUTHOR("John Belmonte"); MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c index 74dd01ae343b..2cb1ea62b4a7 100644 --- a/drivers/platform/x86/toshiba_bluetooth.c +++ b/drivers/platform/x86/toshiba_bluetooth.c @@ -23,14 +23,12 @@ #include #include #include -#include -#include +#include MODULE_AUTHOR("Jes Sorensen "); MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver"); MODULE_LICENSE("GPL"); - static int toshiba_bt_rfkill_add(struct acpi_device *device); static int toshiba_bt_rfkill_remove(struct acpi_device *device); static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event); diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 62e8c221d01e..ba13adea08b0 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -37,8 +37,6 @@ #include #include #include -#include -#include ACPI_MODULE_NAME("wmi"); MODULE_AUTHOR("Carlos Corbacho"); diff --git a/drivers/platform/x86/xo15-ebook.c b/drivers/platform/x86/xo15-ebook.c index 4b1377bd5944..49cbccec6e2d 100644 --- a/drivers/platform/x86/xo15-ebook.c +++ b/drivers/platform/x86/xo15-ebook.c @@ -18,8 +18,7 @@ #include #include #include -#include -#include +#include #define MODULE_NAME "xo15-ebook" diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 14655a0f0431..e869ba698ac0 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -24,7 +24,6 @@ #include #include #include -#include #include "../base.h" #include "pnpacpi.h" diff --git a/drivers/pnp/pnpacpi/pnpacpi.h b/drivers/pnp/pnpacpi/pnpacpi.h index 3e60225b0227..051ef9699777 100644 --- a/drivers/pnp/pnpacpi/pnpacpi.h +++ b/drivers/pnp/pnpacpi/pnpacpi.h @@ -1,7 +1,6 @@ #ifndef ACPI_PNP_H #define ACPI_PNP_H -#include #include #include diff --git a/drivers/sfi/sfi_acpi.c b/drivers/sfi/sfi_acpi.c index f5b4ca581541..5e753d799f61 100644 --- a/drivers/sfi/sfi_acpi.c +++ b/drivers/sfi/sfi_acpi.c @@ -60,7 +60,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include -#include +#include /* FIXME: inclusion should be removed */ #include #include "sfi_core.h" diff --git a/drivers/staging/quickstart/quickstart.c b/drivers/staging/quickstart/quickstart.c index 9f6ebdb23740..a85c3d68c462 100644 --- a/drivers/staging/quickstart/quickstart.c +++ b/drivers/staging/quickstart/quickstart.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 4e243c37f17f..11c656976cb5 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -16,7 +16,6 @@ #include #include #include -#include #include "usb.h" diff --git a/drivers/xen/xen-acpi-cpuhotplug.c b/drivers/xen/xen-acpi-cpuhotplug.c index 8dae6c13063a..cd5bb0a507a2 100644 --- a/drivers/xen/xen-acpi-cpuhotplug.c +++ b/drivers/xen/xen-acpi-cpuhotplug.c @@ -24,10 +24,7 @@ #include #include #include -#include -#include #include - #include #include #include diff --git a/drivers/xen/xen-acpi-memhotplug.c b/drivers/xen/xen-acpi-memhotplug.c index 9083f1e474f8..f2872a1bb096 100644 --- a/drivers/xen/xen-acpi-memhotplug.c +++ b/drivers/xen/xen-acpi-memhotplug.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c index 59708fdd068b..40c4bc06b5fa 100644 --- a/drivers/xen/xen-acpi-pad.c +++ b/drivers/xen/xen-acpi-pad.c @@ -18,11 +18,10 @@ #include #include -#include -#include -#include +#include #include #include +#include #define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad" #define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator" diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index 13bc6c31c060..7231859119f1 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -28,10 +28,8 @@ #include #include #include -#include -#include +#include #include - #include #include #include diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 7b2de026a4f3..510119a63fb2 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -28,8 +28,6 @@ #include -#include - /* TBD: Make dynamic */ #define ACPI_MAX_HANDLES 10 struct acpi_handle_list { diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 1cedfcb1bd88..b124fdb26046 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -26,9 +26,6 @@ #ifndef __ACPI_DRIVERS_H__ #define __ACPI_DRIVERS_H__ -#include -#include - #define ACPI_MAX_STRING 80 /* diff --git a/include/linux/acpi_io.h b/include/linux/acpi_io.h index b0ffa219993e..2a5a1391ce72 100644 --- a/include/linux/acpi_io.h +++ b/include/linux/acpi_io.h @@ -2,7 +2,7 @@ #define _ACPI_IO_H_ #include -#include +#include /* FIXME: inclusion should be removed */ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) diff --git a/include/linux/ide.h b/include/linux/ide.h index 46a14229a162..93b5ca754b5b 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -18,14 +18,10 @@ #include #include #include -#ifdef CONFIG_BLK_DEV_IDEACPI -#include -#endif -#include -#include - /* for request_sense */ #include +#include +#include #if defined(CONFIG_CRIS) || defined(CONFIG_FRV) || defined(CONFIG_MN10300) # define SUPPORT_VLB_SYNC 0 diff --git a/include/linux/iscsi_ibft.h b/include/linux/iscsi_ibft.h index 8ba7e5b9d62c..82f9673c2527 100644 --- a/include/linux/iscsi_ibft.h +++ b/include/linux/iscsi_ibft.h @@ -21,7 +21,7 @@ #ifndef ISCSI_IBFT_H #define ISCSI_IBFT_H -#include +#include /* FIXME: inclusion should be removed */ /* * Logical location of iSCSI Boot Format Table. diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index a2e2f1d17e16..5f2e559af6b0 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -175,8 +175,7 @@ struct hotplug_params { }; #ifdef CONFIG_ACPI -#include -#include +#include int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp); int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags); int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle); diff --git a/include/linux/sfi_acpi.h b/include/linux/sfi_acpi.h index 631af63af42d..2cfcb7944a49 100644 --- a/include/linux/sfi_acpi.h +++ b/include/linux/sfi_acpi.h @@ -60,7 +60,7 @@ #define _LINUX_SFI_ACPI_H #ifdef CONFIG_SFI -#include /* struct acpi_table_header */ +#include /* FIXME: inclusion should be removed */ extern int sfi_acpi_table_parse(char *signature, char *oem_id, char *oem_table_id, diff --git a/include/linux/tboot.h b/include/linux/tboot.h index c75128bed5fa..9a54b331f938 100644 --- a/include/linux/tboot.h +++ b/include/linux/tboot.h @@ -34,7 +34,7 @@ enum { }; #ifdef CONFIG_INTEL_TXT -#include +#include /* used to communicate between tboot and the launched kernel */ #define TB_KEY_SIZE 64 /* 512 bits */ diff --git a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c index 66cace601e57..0f10b81e3322 100644 --- a/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c +++ b/tools/power/cpupower/debug/kernel/cpufreq-test_tsc.c @@ -25,12 +25,9 @@ #include #include #include - +#include #include -#include -#include - static int pm_tmr_ioport = 0; /*helper function to safely read acpi pm timesource*/ -- cgit v1.2.3-59-g8ed1b From 9c5ad36d987a1b06f6b0b9dc7bc61a45d277455d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 Nov 2013 23:58:28 +0100 Subject: ACPI / bind: Redefine acpi_preset_companion() Modify acpi_preset_companion() to take a struct acpi_device pointer instead of an ACPI handle as its second argument and redefine it as a static inline wrapper around ACPI_COMPANION_SET() passing the return value of acpi_find_child_device() directly as the second argument to it. Update its users to pass struct acpi_device pointers instead of ACPI handles to it. This allows some unnecessary acpi_bus_get_device() calls to be avoided. Signed-off-by: Rafael J. Wysocki Reviewed-by: Aaron Lu Tested-by: Aaron Lu # for ATA binding --- drivers/acpi/glue.c | 10 +--------- drivers/ata/libata-acpi.c | 26 +++++++++++++------------- drivers/mmc/core/sdio_bus.c | 2 +- include/acpi/acpi_bus.h | 1 - include/linux/acpi.h | 6 ++++++ 5 files changed, 21 insertions(+), 24 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 12b2acbaa116..c0d18b2145c1 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -149,6 +149,7 @@ struct acpi_device *acpi_find_child_device(struct acpi_device *parent, } return ret; } +EXPORT_SYMBOL_GPL(acpi_find_child_device); acpi_handle acpi_get_child(acpi_handle handle, u64 addr) { @@ -298,15 +299,6 @@ int acpi_unbind_one(struct device *dev) } EXPORT_SYMBOL_GPL(acpi_unbind_one); -void acpi_preset_companion(struct device *dev, acpi_handle parent, u64 addr) -{ - struct acpi_device *adev; - - if (!acpi_bus_get_device(acpi_get_child(parent, addr), &adev)) - ACPI_COMPANION_SET(dev, adev); -} -EXPORT_SYMBOL_GPL(acpi_preset_companion); - static int acpi_platform_notify(struct device *dev) { struct acpi_bus_type *type = acpi_get_bus_type(dev); diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 8e22d9762328..9e69a5308693 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -178,12 +178,12 @@ static const struct acpi_dock_ops ata_acpi_ap_dock_ops = { /* bind acpi handle to pata port */ void ata_acpi_bind_port(struct ata_port *ap) { - acpi_handle host_handle = ACPI_HANDLE(ap->host->dev); + struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); - if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_handle) + if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion) return; - acpi_preset_companion(&ap->tdev, host_handle, ap->port_no); + acpi_preset_companion(&ap->tdev, host_companion, ap->port_no); if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; @@ -196,17 +196,17 @@ void ata_acpi_bind_port(struct ata_port *ap) void ata_acpi_bind_dev(struct ata_device *dev) { struct ata_port *ap = dev->link->ap; - acpi_handle port_handle = ACPI_HANDLE(&ap->tdev); - acpi_handle host_handle = ACPI_HANDLE(ap->host->dev); - acpi_handle parent_handle; + struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev); + struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); + struct acpi_device *parent; u64 adr; /* - * For both sata/pata devices, host handle is required. - * For pata device, port handle is also required. + * For both sata/pata devices, host companion device is required. + * For pata device, port companion device is also required. */ - if (libata_noacpi || !host_handle || - (!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_handle)) + if (libata_noacpi || !host_companion || + (!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_companion)) return; if (ap->flags & ATA_FLAG_ACPI_SATA) { @@ -214,13 +214,13 @@ void ata_acpi_bind_dev(struct ata_device *dev) adr = SATA_ADR(ap->port_no, NO_PORT_MULT); else adr = SATA_ADR(ap->port_no, dev->link->pmp); - parent_handle = host_handle; + parent = host_companion; } else { adr = dev->devno; - parent_handle = port_handle; + parent = port_companion; } - acpi_preset_companion(&dev->tdev, parent_handle, adr); + acpi_preset_companion(&dev->tdev, parent, adr); register_hotplug_dock_device(ata_dev_acpi_handle(dev), &ata_acpi_dev_dock_ops, dev, NULL, NULL); diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 157b570ba343..92d1ba8e8153 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -308,7 +308,7 @@ static void sdio_acpi_set_handle(struct sdio_func *func) struct mmc_host *host = func->card->host; u64 addr = (host->slotno << 16) | func->num; - acpi_preset_companion(&func->dev, ACPI_HANDLE(host->parent), addr); + acpi_preset_companion(&func->dev, ACPI_COMPANION(host->parent), addr); } #else static inline void sdio_acpi_set_handle(struct sdio_func *func) {} diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a1a48f27933a..918eaab892e1 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -435,7 +435,6 @@ struct acpi_pci_root { struct acpi_device *acpi_find_child_device(struct acpi_device *parent, u64 address, bool check_children); acpi_handle acpi_get_child(acpi_handle handle, u64 addr); -void acpi_preset_companion(struct device *dev, acpi_handle parent, u64 addr); int acpi_is_root_bridge(acpi_handle); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d9099b15b472..115c610324d1 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -53,6 +53,12 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev) #define ACPI_COMPANION_SET(dev, adev) ACPI_COMPANION(dev) = (adev) #define ACPI_HANDLE(dev) acpi_device_handle(ACPI_COMPANION(dev)) +static inline void acpi_preset_companion(struct device *dev, + struct acpi_device *parent, u64 addr) +{ + ACPI_COMPANION_SET(dev, acpi_find_child_device(parent, addr, NULL)); +} + static inline const char *acpi_dev_name(struct acpi_device *adev) { return dev_name(&adev->dev); -- cgit v1.2.3-59-g8ed1b From c099eacbcaec4475936fbf73e499507728ce47e1 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 6 Dec 2013 16:51:59 +0800 Subject: SFI / ACPI: Fix warnings reported during builds with W=1 The following warnings can be seen in W=1 builds, because the original sfi_acpi.[ch] header inclusions are incorrect: include/linux/sfi_acpi.h:72:2: error: implicit declaration of function 'acpi_table_parse' [-Werror=implicit-function-declaration] drivers/sfi/sfi_acpi.c:154:5: warning: no previous prototype for 'sfi_acpi_table_parse' [-Wmissing-prototypes] Fix linux/sfi_acpi.h and modify drivers/sfi/sfi_acpi.c accordingly. Reported-by: Andy Shevchenko Signed-off-by: Lv Zheng [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- arch/x86/pci/mmconfig-shared.c | 1 - drivers/sfi/sfi_acpi.c | 4 +--- include/linux/sfi_acpi.h | 3 +++ 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 082e88129712..248642f4bab7 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/drivers/sfi/sfi_acpi.c b/drivers/sfi/sfi_acpi.c index 5e753d799f61..d277b36eb389 100644 --- a/drivers/sfi/sfi_acpi.c +++ b/drivers/sfi/sfi_acpi.c @@ -60,9 +60,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include -#include /* FIXME: inclusion should be removed */ - -#include +#include #include "sfi_core.h" /* diff --git a/include/linux/sfi_acpi.h b/include/linux/sfi_acpi.h index 2cfcb7944a49..4723bbfa1c26 100644 --- a/include/linux/sfi_acpi.h +++ b/include/linux/sfi_acpi.h @@ -59,6 +59,9 @@ #ifndef _LINUX_SFI_ACPI_H #define _LINUX_SFI_ACPI_H +#include +#include + #ifdef CONFIG_SFI #include /* FIXME: inclusion should be removed */ -- cgit v1.2.3-59-g8ed1b From 27d50c82714f6477ac690034b37d202f76eb4f70 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 6 Dec 2013 16:52:05 +0800 Subject: ACPI / i915: Fix incorrect inclusions via To avoid build problems and breaking dependencies between ACPI header files, should not be included directly by code outside of the ACPI core subsystem. However, that is possible if is included, because that file contains a direct inclusion of . For this reason, remove the direct inclusion from , move that file from include/linux/ to include/acpi/ and make include it for CONFIG_ACPI set along with the other ACPI header files. Accordingly, Remove the inclusions of from everywhere. Of course, that causes the contents of the new file to be available for CONFIG_ACPI set only, so intel_opregion.o that depends on it should also depend on CONFIG_ACPI (and it really should not be compiled for CONFIG_ACPI unset anyway). References: https://01.org/linuxgraphics/sites/default/files/documentation/acpi_igd_opregion_spec.pdf Cc: Matthew Garrett Signed-off-by: Lv Zheng Acked-by: Daniel Vetter [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/apei/apei-base.c | 1 - drivers/acpi/apei/apei-internal.h | 1 - drivers/acpi/apei/ghes.c | 1 - drivers/acpi/nvs.c | 1 - drivers/acpi/osl.c | 1 - drivers/gpu/drm/gma500/opregion.c | 1 - drivers/gpu/drm/i915/Makefile | 3 +-- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/intel_opregion.c | 1 - include/acpi/acpi_io.h | 17 +++++++++++++++++ include/linux/acpi.h | 1 + include/linux/acpi_io.h | 18 ------------------ 12 files changed, 21 insertions(+), 28 deletions(-) create mode 100644 include/acpi/acpi_io.h delete mode 100644 include/linux/acpi_io.h (limited to 'include/linux') diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index 6d2c49b86b7f..0760b75f79cc 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index 21ba34a73883..e5bcd919d4e6 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -8,7 +8,6 @@ #include #include -#include struct apei_exec_context; diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index a30bc313787b..694c486a12ed 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index 386a9fe497b4..ef28613d5192 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -12,7 +12,6 @@ #include #include #include -#include /* ACPI NVS regions, APEI may use it */ diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 244be2affea7..064b8b365060 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/gma500/opregion.c b/drivers/gpu/drm/gma500/opregion.c index ad0d6de938f3..13ec6283bf59 100644 --- a/drivers/gpu/drm/gma500/opregion.c +++ b/drivers/gpu/drm/gma500/opregion.c @@ -22,7 +22,6 @@ * */ #include -#include #include "psb_drv.h" #include "psb_intel_reg.h" diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 41838eaa799c..d4ae48b04cf2 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -38,7 +38,6 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ intel_ringbuffer.o \ intel_overlay.o \ intel_sprite.o \ - intel_opregion.o \ intel_sideband.o \ intel_uncore.o \ dvo_ch7xxx.o \ @@ -51,7 +50,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ i915-$(CONFIG_COMPAT) += i915_ioc32.o -i915-$(CONFIG_ACPI) += intel_acpi.o +i915-$(CONFIG_ACPI) += intel_acpi.o intel_opregion.o i915-$(CONFIG_DRM_I915_FBDEV) += intel_fbdev.o diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ccdbecca070d..7f37b838802e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2336,8 +2336,8 @@ extern void intel_i2c_reset(struct drm_device *dev); /* intel_opregion.c */ struct intel_encoder; -extern int intel_opregion_setup(struct drm_device *dev); #ifdef CONFIG_ACPI +extern int intel_opregion_setup(struct drm_device *dev); extern void intel_opregion_init(struct drm_device *dev); extern void intel_opregion_fini(struct drm_device *dev); extern void intel_opregion_asle_intr(struct drm_device *dev); @@ -2346,6 +2346,7 @@ extern int intel_opregion_notify_encoder(struct intel_encoder *intel_encoder, extern int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state); #else +static inline int intel_opregion_setup(struct drm_device *dev) { return 0; } static inline void intel_opregion_init(struct drm_device *dev) { return; } static inline void intel_opregion_fini(struct drm_device *dev) { return; } static inline void intel_opregion_asle_intr(struct drm_device *dev) { return; } diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 6d69a9bad865..9a8804bee5cd 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -28,7 +28,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include diff --git a/include/acpi/acpi_io.h b/include/acpi/acpi_io.h new file mode 100644 index 000000000000..2be858018c7f --- /dev/null +++ b/include/acpi/acpi_io.h @@ -0,0 +1,17 @@ +#ifndef _ACPI_IO_H_ +#define _ACPI_IO_H_ + +#include + +static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, + acpi_size size) +{ + return ioremap_cache(phys, size); +} + +void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size); + +int acpi_os_map_generic_address(struct acpi_generic_address *addr); +void acpi_os_unmap_generic_address(struct acpi_generic_address *addr); + +#endif diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d9099b15b472..726a6aa62b64 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -42,6 +42,7 @@ #include #include #include +#include #include static inline acpi_handle acpi_device_handle(struct acpi_device *adev) diff --git a/include/linux/acpi_io.h b/include/linux/acpi_io.h deleted file mode 100644 index 2a5a1391ce72..000000000000 --- a/include/linux/acpi_io.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _ACPI_IO_H_ -#define _ACPI_IO_H_ - -#include -#include /* FIXME: inclusion should be removed */ - -static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, - acpi_size size) -{ - return ioremap_cache(phys, size); -} - -void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size); - -int acpi_os_map_generic_address(struct acpi_generic_address *addr); -void acpi_os_unmap_generic_address(struct acpi_generic_address *addr); - -#endif -- cgit v1.2.3-59-g8ed1b From 9d24622ced329e35e2349ef419355a87d94be61f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Fri, 6 Dec 2013 16:52:19 +0800 Subject: ACPI / IBFT: Fix incorrect inclusion in iSCSI boot firmware module To avoid build problems and breaking dependencies between ACPI header files, should not be included directly by code outside of the ACPI core subsystem, but this is done by the ACPI iSCSI Boot Firmware code. The iBFT specification doesn't mention whether or not it can appear on a non-ACPI platform, but is says that ACPI 3.0b defines the mechanism. The current CONFIG_ISCSI_IBFT_FIND code doesn't use the ACPI tables API to locate the table, so it doesn't rely on CONFIG_ACPI directly. However, since iBFT is is an ACPI-based mechanism (please refer to the documentation link below for more information), it should be correct to make CONFIG_ISCSI_IBFT_FIND depend on CONFIG_ACPI (even though the table location can be implemented without using ACPI tables API). After that change, include/linux/iscsi_ibft.h can be modified to include instead of as appropriate. References: http://www.microsoft.com/whdc/system/platform/firmware/ibft.mspx Cc: Konrad Rzeszutek Wilk Cc: Peter Jones Signed-off-by: Lv Zheng [rjw: Subject and changelog] Signed-off-by: Rafael J. Wysocki --- drivers/firmware/Kconfig | 2 +- include/linux/iscsi_ibft.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 074787281c94..a6ef6acaa1c8 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -110,7 +110,7 @@ config DMI_SYSFS config ISCSI_IBFT_FIND bool "iSCSI Boot Firmware Table Attributes" - depends on X86 + depends on X86 && ACPI default n help This option enables the kernel to find the region of memory diff --git a/include/linux/iscsi_ibft.h b/include/linux/iscsi_ibft.h index 82f9673c2527..605cc5c333d9 100644 --- a/include/linux/iscsi_ibft.h +++ b/include/linux/iscsi_ibft.h @@ -21,7 +21,7 @@ #ifndef ISCSI_IBFT_H #define ISCSI_IBFT_H -#include /* FIXME: inclusion should be removed */ +#include /* * Logical location of iSCSI Boot Format Table. -- cgit v1.2.3-59-g8ed1b From cb955852a48c29ef7bd847ce993102e2b58295d4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 7 Dec 2013 10:45:00 +0000 Subject: iio: Remove support for the legacy event config interface Now that all drivers have been converted to the new event config interface we can remove for the legacy event config interface. Also drop the '_new' suffix for the event config interface callbacks, since those are the only callbacks now. Signed-off-by: Lars-Peter Clausen Signed-off-by: Jonathan Cameron --- drivers/iio/adc/max1363.c | 8 +- drivers/iio/dac/ad5421.c | 6 +- drivers/iio/industrialio-event.c | 154 +++++------------------------ drivers/iio/light/apds9300.c | 8 +- drivers/iio/light/cm36651.c | 8 +- drivers/iio/light/gp2ap020a00f.c | 8 +- drivers/iio/light/tsl2563.c | 8 +- drivers/staging/iio/accel/lis3l02dq_core.c | 8 +- drivers/staging/iio/accel/sca3000_core.c | 16 +-- drivers/staging/iio/adc/ad7291.c | 8 +- drivers/staging/iio/adc/ad799x_core.c | 6 +- drivers/staging/iio/cdc/ad7150.c | 8 +- drivers/staging/iio/iio_simple_dummy.c | 8 +- drivers/staging/iio/light/tsl2x7x_core.c | 40 ++++---- include/linux/iio/events.h | 4 - include/linux/iio/iio.h | 34 +------ 16 files changed, 97 insertions(+), 235 deletions(-) (limited to 'include/linux') diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index 6118dced02b6..e283f2f2ee2f 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1039,10 +1039,10 @@ static const struct iio_info max1238_info = { }; static const struct iio_info max1363_info = { - .read_event_value_new = &max1363_read_thresh, - .write_event_value_new = &max1363_write_thresh, - .read_event_config_new = &max1363_read_event_config, - .write_event_config_new = &max1363_write_event_config, + .read_event_value = &max1363_read_thresh, + .write_event_value = &max1363_write_thresh, + .read_event_config = &max1363_read_event_config, + .write_event_config = &max1363_write_event_config, .read_raw = &max1363_read_raw, .update_scan_mode = &max1363_update_scan_mode, .driver_module = THIS_MODULE, diff --git a/drivers/iio/dac/ad5421.c b/drivers/iio/dac/ad5421.c index 59a0cb51265c..1cb15d8e94b7 100644 --- a/drivers/iio/dac/ad5421.c +++ b/drivers/iio/dac/ad5421.c @@ -458,9 +458,9 @@ static int ad5421_read_event_value(struct iio_dev *indio_dev, static const struct iio_info ad5421_info = { .read_raw = ad5421_read_raw, .write_raw = ad5421_write_raw, - .read_event_config_new = ad5421_read_event_config, - .write_event_config_new = ad5421_write_event_config, - .read_event_value_new = ad5421_read_event_value, + .read_event_config = ad5421_read_event_config, + .write_event_config = ad5421_write_event_config, + .read_event_value = ad5421_read_event_value, .driver_module = THIS_MODULE, }; diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c index bc043fab4cd1..c9c1419fe6e0 100644 --- a/drivers/iio/industrialio-event.c +++ b/drivers/iio/industrialio-event.c @@ -242,13 +242,9 @@ static ssize_t iio_ev_state_store(struct device *dev, if (ret < 0) return ret; - if (indio_dev->info->write_event_config) - ret = indio_dev->info->write_event_config(indio_dev, - this_attr->address, val); - else - ret = indio_dev->info->write_event_config_new(indio_dev, - this_attr->c, iio_ev_attr_type(this_attr), - iio_ev_attr_dir(this_attr), val); + ret = indio_dev->info->write_event_config(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr), val); return (ret < 0) ? ret : len; } @@ -261,13 +257,9 @@ static ssize_t iio_ev_state_show(struct device *dev, struct iio_dev_attr *this_attr = to_iio_dev_attr(attr); int val; - if (indio_dev->info->read_event_config) - val = indio_dev->info->read_event_config(indio_dev, - this_attr->address); - else - val = indio_dev->info->read_event_config_new(indio_dev, - this_attr->c, iio_ev_attr_type(this_attr), - iio_ev_attr_dir(this_attr)); + val = indio_dev->info->read_event_config(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr)); if (val < 0) return val; else @@ -283,21 +275,13 @@ static ssize_t iio_ev_value_show(struct device *dev, int val, val2; int ret; - if (indio_dev->info->read_event_value) { - ret = indio_dev->info->read_event_value(indio_dev, - this_attr->address, &val); - if (ret < 0) - return ret; - return sprintf(buf, "%d\n", val); - } else { - ret = indio_dev->info->read_event_value_new(indio_dev, - this_attr->c, iio_ev_attr_type(this_attr), - iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr), - &val, &val2); - if (ret < 0) - return ret; - return iio_format_value(buf, ret, val, val2); - } + ret = indio_dev->info->read_event_value(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr), + &val, &val2); + if (ret < 0) + return ret; + return iio_format_value(buf, ret, val, val2); } static ssize_t iio_ev_value_store(struct device *dev, @@ -310,25 +294,16 @@ static ssize_t iio_ev_value_store(struct device *dev, int val, val2; int ret; - if (!indio_dev->info->write_event_value && - !indio_dev->info->write_event_value_new) + if (!indio_dev->info->write_event_value) return -EINVAL; - if (indio_dev->info->write_event_value) { - ret = kstrtoint(buf, 10, &val); - if (ret) - return ret; - ret = indio_dev->info->write_event_value(indio_dev, - this_attr->address, val); - } else { - ret = iio_str_to_fixpoint(buf, 100000, &val, &val2); - if (ret) - return ret; - ret = indio_dev->info->write_event_value_new(indio_dev, - this_attr->c, iio_ev_attr_type(this_attr), - iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr), - val, val2); - } + ret = iio_str_to_fixpoint(buf, 100000, &val, &val2); + if (ret) + return ret; + ret = indio_dev->info->write_event_value(indio_dev, + this_attr->c, iio_ev_attr_type(this_attr), + iio_ev_attr_dir(this_attr), iio_ev_attr_info(this_attr), + val, val2); if (ret < 0) return ret; @@ -377,7 +352,7 @@ static int iio_device_add_event(struct iio_dev *indio_dev, return attrcount; } -static int iio_device_add_event_sysfs_new(struct iio_dev *indio_dev, +static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, struct iio_chan_spec const *chan) { int ret = 0, i, attrcount = 0; @@ -420,89 +395,6 @@ error_ret: return ret; } -static int iio_device_add_event_sysfs_old(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan) -{ - int ret = 0, i, attrcount = 0; - u64 mask = 0; - char *postfix; - if (!chan->event_mask) - return 0; - - for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) { - postfix = kasprintf(GFP_KERNEL, "%s_%s_en", - iio_ev_type_text[i/IIO_EV_DIR_MAX], - iio_ev_dir_text[i%IIO_EV_DIR_MAX]); - if (postfix == NULL) { - ret = -ENOMEM; - goto error_ret; - } - if (chan->modified) - mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel2, - i/IIO_EV_DIR_MAX, - i%IIO_EV_DIR_MAX); - else if (chan->differential) - mask = IIO_EVENT_CODE(chan->type, - 0, 0, - i%IIO_EV_DIR_MAX, - i/IIO_EV_DIR_MAX, - 0, - chan->channel, - chan->channel2); - else - mask = IIO_UNMOD_EVENT_CODE(chan->type, - chan->channel, - i/IIO_EV_DIR_MAX, - i%IIO_EV_DIR_MAX); - - ret = __iio_add_chan_devattr(postfix, - chan, - &iio_ev_state_show, - iio_ev_state_store, - mask, - 0, - &indio_dev->dev, - &indio_dev->event_interface-> - dev_attr_list); - kfree(postfix); - if (ret) - goto error_ret; - attrcount++; - postfix = kasprintf(GFP_KERNEL, "%s_%s_value", - iio_ev_type_text[i/IIO_EV_DIR_MAX], - iio_ev_dir_text[i%IIO_EV_DIR_MAX]); - if (postfix == NULL) { - ret = -ENOMEM; - goto error_ret; - } - ret = __iio_add_chan_devattr(postfix, chan, - iio_ev_value_show, - iio_ev_value_store, - mask, - 0, - &indio_dev->dev, - &indio_dev->event_interface-> - dev_attr_list); - kfree(postfix); - if (ret) - goto error_ret; - attrcount++; - } - ret = attrcount; -error_ret: - return ret; -} - - -static int iio_device_add_event_sysfs(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan) -{ - if (chan->event_mask) - return iio_device_add_event_sysfs_old(indio_dev, chan); - else - return iio_device_add_event_sysfs_new(indio_dev, chan); -} - static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev) { int j, ret, attrcount = 0; @@ -523,8 +415,6 @@ static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev) int j; for (j = 0; j < indio_dev->num_channels; j++) { - if (indio_dev->channels[j].event_mask != 0) - return true; if (indio_dev->channels[j].num_event_specs != 0) return true; } diff --git a/drivers/iio/light/apds9300.c b/drivers/iio/light/apds9300.c index 51097bbd59c9..9ddde0ca9c34 100644 --- a/drivers/iio/light/apds9300.c +++ b/drivers/iio/light/apds9300.c @@ -344,10 +344,10 @@ static const struct iio_info apds9300_info_no_irq = { static const struct iio_info apds9300_info = { .driver_module = THIS_MODULE, .read_raw = apds9300_read_raw, - .read_event_value_new = apds9300_read_thresh, - .write_event_value_new = apds9300_write_thresh, - .read_event_config_new = apds9300_read_interrupt_config, - .write_event_config_new = apds9300_write_interrupt_config, + .read_event_value = apds9300_read_thresh, + .write_event_value = apds9300_write_thresh, + .read_event_config = apds9300_read_interrupt_config, + .write_event_config = apds9300_write_interrupt_config, }; static const struct iio_event_spec apds9300_event_spec[] = { diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 2a0eb8de3396..000cc8eb362d 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -614,10 +614,10 @@ static const struct iio_info cm36651_info = { .driver_module = THIS_MODULE, .read_raw = &cm36651_read_raw, .write_raw = &cm36651_write_raw, - .read_event_value_new = &cm36651_read_prox_thresh, - .write_event_value_new = &cm36651_write_prox_thresh, - .read_event_config_new = &cm36651_read_prox_event_config, - .write_event_config_new = &cm36651_write_prox_event_config, + .read_event_value = &cm36651_read_prox_thresh, + .write_event_value = &cm36651_write_prox_thresh, + .read_event_config = &cm36651_read_prox_event_config, + .write_event_config = &cm36651_write_prox_event_config, .attrs = &cm36651_attribute_group, }; diff --git a/drivers/iio/light/gp2ap020a00f.c b/drivers/iio/light/gp2ap020a00f.c index dc79835be308..5ea4a03c7e71 100644 --- a/drivers/iio/light/gp2ap020a00f.c +++ b/drivers/iio/light/gp2ap020a00f.c @@ -1388,10 +1388,10 @@ static const struct iio_chan_spec gp2ap020a00f_channels[] = { static const struct iio_info gp2ap020a00f_info = { .read_raw = &gp2ap020a00f_read_raw, - .read_event_value_new = &gp2ap020a00f_read_event_val, - .read_event_config_new = &gp2ap020a00f_read_event_config, - .write_event_value_new = &gp2ap020a00f_write_event_val, - .write_event_config_new = &gp2ap020a00f_write_event_config, + .read_event_value = &gp2ap020a00f_read_event_val, + .read_event_config = &gp2ap020a00f_read_event_config, + .write_event_value = &gp2ap020a00f_write_event_val, + .write_event_config = &gp2ap020a00f_write_event_config, .driver_module = THIS_MODULE, }; diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index 0c6e459c86b1..3d8110157f2d 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -702,10 +702,10 @@ static const struct iio_info tsl2563_info = { .driver_module = THIS_MODULE, .read_raw = &tsl2563_read_raw, .write_raw = &tsl2563_write_raw, - .read_event_value_new = &tsl2563_read_thresh, - .write_event_value_new = &tsl2563_write_thresh, - .read_event_config_new = &tsl2563_read_interrupt_config, - .write_event_config_new = &tsl2563_write_interrupt_config, + .read_event_value = &tsl2563_read_thresh, + .write_event_value = &tsl2563_write_thresh, + .read_event_config = &tsl2563_read_interrupt_config, + .write_event_config = &tsl2563_write_interrupt_config, }; static int tsl2563_probe(struct i2c_client *client, diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index 735c0a34fa93..898653c09279 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -676,10 +676,10 @@ static const struct attribute_group lis3l02dq_attribute_group = { static const struct iio_info lis3l02dq_info = { .read_raw = &lis3l02dq_read_raw, .write_raw = &lis3l02dq_write_raw, - .read_event_value_new = &lis3l02dq_read_thresh, - .write_event_value_new = &lis3l02dq_write_thresh, - .write_event_config_new = &lis3l02dq_write_event_config, - .read_event_config_new = &lis3l02dq_read_event_config, + .read_event_value = &lis3l02dq_read_thresh, + .write_event_value = &lis3l02dq_write_thresh, + .write_event_config = &lis3l02dq_write_event_config, + .read_event_config = &lis3l02dq_read_event_config, .driver_module = THIS_MODULE, .attrs = &lis3l02dq_attribute_group, }; diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index c49e6ef9d05f..7f6ccdfaf168 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -1126,20 +1126,20 @@ static const struct iio_info sca3000_info = { .attrs = &sca3000_attribute_group, .read_raw = &sca3000_read_raw, .event_attrs = &sca3000_event_attribute_group, - .read_event_value_new = &sca3000_read_thresh, - .write_event_value_new = &sca3000_write_thresh, - .read_event_config_new = &sca3000_read_event_config, - .write_event_config_new = &sca3000_write_event_config, + .read_event_value = &sca3000_read_thresh, + .write_event_value = &sca3000_write_thresh, + .read_event_config = &sca3000_read_event_config, + .write_event_config = &sca3000_write_event_config, .driver_module = THIS_MODULE, }; static const struct iio_info sca3000_info_with_temp = { .attrs = &sca3000_attribute_group_with_temp, .read_raw = &sca3000_read_raw, - .read_event_value_new = &sca3000_read_thresh, - .write_event_value_new = &sca3000_write_thresh, - .read_event_config_new = &sca3000_read_event_config, - .write_event_config_new = &sca3000_write_event_config, + .read_event_value = &sca3000_read_thresh, + .write_event_value = &sca3000_write_thresh, + .read_event_config = &sca3000_read_event_config, + .write_event_config = &sca3000_write_event_config, .driver_module = THIS_MODULE, }; diff --git a/drivers/staging/iio/adc/ad7291.c b/drivers/staging/iio/adc/ad7291.c index d13f8aeeb62f..357cef2a6f4c 100644 --- a/drivers/staging/iio/adc/ad7291.c +++ b/drivers/staging/iio/adc/ad7291.c @@ -452,10 +452,10 @@ static const struct iio_chan_spec ad7291_channels[] = { static const struct iio_info ad7291_info = { .read_raw = &ad7291_read_raw, - .read_event_config_new = &ad7291_read_event_config, - .write_event_config_new = &ad7291_write_event_config, - .read_event_value_new = &ad7291_read_event_value, - .write_event_value_new = &ad7291_write_event_value, + .read_event_config = &ad7291_read_event_config, + .write_event_config = &ad7291_write_event_config, + .read_event_value = &ad7291_read_event_value, + .write_event_value = &ad7291_write_event_value, .driver_module = THIS_MODULE, }; diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c index 9428be82b655..5ea36410f716 100644 --- a/drivers/staging/iio/adc/ad799x_core.c +++ b/drivers/staging/iio/adc/ad799x_core.c @@ -377,9 +377,9 @@ static const struct iio_info ad7991_info = { static const struct iio_info ad7993_4_7_8_info = { .read_raw = &ad799x_read_raw, .event_attrs = &ad799x_event_attrs_group, - .read_event_config_new = &ad799x_read_event_config, - .read_event_value_new = &ad799x_read_event_value, - .write_event_value_new = &ad799x_write_event_value, + .read_event_config = &ad799x_read_event_config, + .read_event_value = &ad799x_read_event_value, + .write_event_value = &ad799x_write_event_value, .driver_module = THIS_MODULE, .update_scan_mode = ad7997_8_update_scan_mode, }; diff --git a/drivers/staging/iio/cdc/ad7150.c b/drivers/staging/iio/cdc/ad7150.c index 7e7f9890a642..047af2376300 100644 --- a/drivers/staging/iio/cdc/ad7150.c +++ b/drivers/staging/iio/cdc/ad7150.c @@ -576,10 +576,10 @@ static const struct iio_info ad7150_info = { .event_attrs = &ad7150_event_attribute_group, .driver_module = THIS_MODULE, .read_raw = &ad7150_read_raw, - .read_event_config_new = &ad7150_read_event_config, - .write_event_config_new = &ad7150_write_event_config, - .read_event_value_new = &ad7150_read_event_value, - .write_event_value_new = &ad7150_write_event_value, + .read_event_config = &ad7150_read_event_config, + .write_event_config = &ad7150_write_event_config, + .read_event_value = &ad7150_read_event_value, + .write_event_value = &ad7150_write_event_value, }; /* diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c index 1fac9894b18c..fd334a03a49a 100644 --- a/drivers/staging/iio/iio_simple_dummy.c +++ b/drivers/staging/iio/iio_simple_dummy.c @@ -370,10 +370,10 @@ static const struct iio_info iio_dummy_info = { .read_raw = &iio_dummy_read_raw, .write_raw = &iio_dummy_write_raw, #ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS - .read_event_config_new = &iio_simple_dummy_read_event_config, - .write_event_config_new = &iio_simple_dummy_write_event_config, - .read_event_value_new = &iio_simple_dummy_read_event_value, - .write_event_value_new = &iio_simple_dummy_write_event_value, + .read_event_config = &iio_simple_dummy_read_event_config, + .write_event_config = &iio_simple_dummy_write_event_config, + .read_event_value = &iio_simple_dummy_read_event_value, + .write_event_value = &iio_simple_dummy_write_event_value, #endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */ }; diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c index 18805029d2a9..1e538086d48b 100644 --- a/drivers/staging/iio/light/tsl2x7x_core.c +++ b/drivers/staging/iio/light/tsl2x7x_core.c @@ -1672,10 +1672,10 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value_new = &tsl2x7x_read_thresh, - .write_event_value_new = &tsl2x7x_write_thresh, - .read_event_config_new = &tsl2x7x_read_interrupt_config, - .write_event_config_new = &tsl2x7x_write_interrupt_config, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, }, [PRX] = { .attrs = &tsl2X7X_device_attr_group_tbl[PRX], @@ -1683,10 +1683,10 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value_new = &tsl2x7x_read_thresh, - .write_event_value_new = &tsl2x7x_write_thresh, - .read_event_config_new = &tsl2x7x_read_interrupt_config, - .write_event_config_new = &tsl2x7x_write_interrupt_config, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, }, [ALSPRX] = { .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX], @@ -1694,10 +1694,10 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value_new = &tsl2x7x_read_thresh, - .write_event_value_new = &tsl2x7x_write_thresh, - .read_event_config_new = &tsl2x7x_read_interrupt_config, - .write_event_config_new = &tsl2x7x_write_interrupt_config, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, }, [PRX2] = { .attrs = &tsl2X7X_device_attr_group_tbl[PRX2], @@ -1705,10 +1705,10 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value_new = &tsl2x7x_read_thresh, - .write_event_value_new = &tsl2x7x_write_thresh, - .read_event_config_new = &tsl2x7x_read_interrupt_config, - .write_event_config_new = &tsl2x7x_write_interrupt_config, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, }, [ALSPRX2] = { .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX2], @@ -1716,10 +1716,10 @@ static const struct iio_info tsl2X7X_device_info[] = { .driver_module = THIS_MODULE, .read_raw = &tsl2x7x_read_raw, .write_raw = &tsl2x7x_write_raw, - .read_event_value_new = &tsl2x7x_read_thresh, - .write_event_value_new = &tsl2x7x_write_thresh, - .read_event_config_new = &tsl2x7x_read_interrupt_config, - .write_event_config_new = &tsl2x7x_write_interrupt_config, + .read_event_value = &tsl2x7x_read_thresh, + .write_event_value = &tsl2x7x_write_thresh, + .read_event_config = &tsl2x7x_read_interrupt_config, + .write_event_config = &tsl2x7x_write_interrupt_config, }, }; diff --git a/include/linux/iio/events.h b/include/linux/iio/events.h index 5dab2c41031f..8bbd7bc1043d 100644 --- a/include/linux/iio/events.h +++ b/include/linux/iio/events.h @@ -46,10 +46,6 @@ struct iio_event_data { ((u16)chan)) -#define IIO_EV_DIR_MAX 4 -#define IIO_EV_BIT(type, direction) \ - (1 << (type*IIO_EV_DIR_MAX + direction)) - /** * IIO_MOD_EVENT_CODE() - create event identifier for modified channels * @chan_type: Type of the channel. Should be one of enum iio_chan_type. diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index 5b125fd554e4..75a8a20c8179 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -185,7 +185,6 @@ struct iio_event_spec { * by all channels of the same direction. * @info_mask_shared_by_all: What information is to be exported that is shared * by all channels. - * @event_mask: What events can this channel produce. * @event_spec: Array of events which should be registered for this * channel. * @num_event_specs: Size of the event_spec array. @@ -226,7 +225,6 @@ struct iio_chan_spec { long info_mask_shared_by_type; long info_mask_shared_by_dir; long info_mask_shared_by_all; - long event_mask; const struct iio_event_spec *event_spec; unsigned int num_event_specs; const struct iio_chan_spec_ext_info *ext_info; @@ -307,16 +305,8 @@ struct iio_dev; * returns IIO_VAL_INT_PLUS_MICRO. * @read_event_config: find out if the event is enabled. * @write_event_config: set if the event is enabled. - * @read_event_value: read a value associated with the event. Meaning - * is event dependant. event_code specifies which event. - * @write_event_value: write the value associated with the event. - * Meaning is event dependent. - * @read_event_config_new: find out if the event is enabled. New style interface. - * @write_event_config_new: set if the event is enabled. New style interface. - * @read_event_value_new: read a configuration value associated with the event. - * New style interface. - * @write_event_value_new: write a configuration value for the event. New style - * interface. + * @read_event_value: read a configuration value associated with the event. + * @write_event_value: write a configuration value for the event. * @validate_trigger: function to validate the trigger when the * current trigger gets changed. * @update_scan_mode: function to configure device and scan buffer when @@ -345,37 +335,23 @@ struct iio_info { long mask); int (*read_event_config)(struct iio_dev *indio_dev, - u64 event_code); - - int (*write_event_config)(struct iio_dev *indio_dev, - u64 event_code, - int state); - - int (*read_event_value)(struct iio_dev *indio_dev, - u64 event_code, - int *val); - int (*write_event_value)(struct iio_dev *indio_dev, - u64 event_code, - int val); - - int (*read_event_config_new)(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir); - int (*write_event_config_new)(struct iio_dev *indio_dev, + int (*write_event_config)(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, int state); - int (*read_event_value_new)(struct iio_dev *indio_dev, + int (*read_event_value)(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, enum iio_event_info info, int *val, int *val2); - int (*write_event_value_new)(struct iio_dev *indio_dev, + int (*write_event_value)(struct iio_dev *indio_dev, const struct iio_chan_spec *chan, enum iio_event_type type, enum iio_event_direction dir, -- cgit v1.2.3-59-g8ed1b From 5877231f646bbd6d1d545e7af83aaa6e6b746013 Mon Sep 17 00:00:00 2001 From: "Aneesh Kumar K.V" Date: Fri, 6 Dec 2013 00:08:22 +0530 Subject: mm: Move change_prot_numa outside CONFIG_ARCH_USES_NUMA_PROT_NONE change_prot_numa should work even if _PAGE_NUMA != _PAGE_PROTNONE. On archs like ppc64 that don't use _PAGE_PROTNONE and also have a separate page table outside linux pagetable, we just need to make sure that when calling change_prot_numa we flush the hardware page table entry so that next page access result in a numa fault. We still need to make sure we use the numa faulting logic only when CONFIG_NUMA_BALANCING is set. This implies the migrate-on-fault (Lazy migration) via mbind will only work if CONFIG_NUMA_BALANCING is set. Signed-off-by: Aneesh Kumar K.V Reviewed-by: Rik van Riel Acked-by: Mel Gorman Signed-off-by: Benjamin Herrenschmidt --- include/linux/mm.h | 2 +- mm/mempolicy.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mm.h b/include/linux/mm.h index 1cedd000cf29..a7b4e310bf42 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1842,7 +1842,7 @@ static inline pgprot_t vm_get_page_prot(unsigned long vm_flags) } #endif -#ifdef CONFIG_ARCH_USES_NUMA_PROT_NONE +#ifdef CONFIG_NUMA_BALANCING unsigned long change_prot_numa(struct vm_area_struct *vma, unsigned long start, unsigned long end); #endif diff --git a/mm/mempolicy.c b/mm/mempolicy.c index eca4a3129129..9f73b29d304d 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -613,7 +613,7 @@ static inline int queue_pages_pgd_range(struct vm_area_struct *vma, return 0; } -#ifdef CONFIG_ARCH_USES_NUMA_PROT_NONE +#ifdef CONFIG_NUMA_BALANCING /* * This is used to mark a range of virtual addresses to be inaccessible. * These are later cleared by a NUMA hinting fault. Depending on these @@ -627,7 +627,6 @@ unsigned long change_prot_numa(struct vm_area_struct *vma, unsigned long addr, unsigned long end) { int nr_updated; - BUILD_BUG_ON(_PAGE_NUMA != _PAGE_PROTNONE); nr_updated = change_protection(vma, addr, end, vma->vm_page_prot, 0, 1); if (nr_updated) @@ -641,7 +640,7 @@ static unsigned long change_prot_numa(struct vm_area_struct *vma, { return 0; } -#endif /* CONFIG_ARCH_USES_NUMA_PROT_NONE */ +#endif /* CONFIG_NUMA_BALANCING */ /* * Walk through page tables and collect pages to be migrated. -- cgit v1.2.3-59-g8ed1b From 82f91fe092b6eacd82e976b8955443f9fd97d07e Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 2 Dec 2013 13:56:03 -0500 Subject: tty: Always handle NULL flag ptr Most line disciplines already handle the undocumented NULL flag ptr in their .receive_buf method; however, several don't. Document the NULL flag ptr, and correct handling in the N_MOUSE, N_GSM0710 and N_R394 line disciplines. Signed-off-by: Peter Hurley Acked-by: Dmitry Torokhov Signed-off-by: Greg Kroah-Hartman --- drivers/input/serio/serport.c | 28 +++++++++++++++------------- drivers/tty/n_gsm.c | 5 +++-- drivers/tty/n_r3964.c | 2 +- include/linux/tty_ldisc.h | 6 ++++-- 4 files changed, 23 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 8755f5f3ad37..0cb7ef59071b 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -124,7 +124,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c { struct serport *serport = (struct serport*) tty->disc_data; unsigned long flags; - unsigned int ch_flags; + unsigned int ch_flags = 0; int i; spin_lock_irqsave(&serport->lock, flags); @@ -133,18 +133,20 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c goto out; for (i = 0; i < count; i++) { - switch (fp[i]) { - case TTY_FRAME: - ch_flags = SERIO_FRAME; - break; - - case TTY_PARITY: - ch_flags = SERIO_PARITY; - break; - - default: - ch_flags = 0; - break; + if (fp) { + switch (fp[i]) { + case TTY_FRAME: + ch_flags = SERIO_FRAME; + break; + + case TTY_PARITY: + ch_flags = SERIO_PARITY; + break; + + default: + ch_flags = 0; + break; + } } serio_interrupt(serport->serio, cp[i], ch_flags); diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index c0f76da55304..c09db11b8831 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2269,14 +2269,15 @@ static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *f; int i; char buf[64]; - char flags; + char flags = TTY_NORMAL; if (debug & 4) print_hex_dump_bytes("gsmld_receive: ", DUMP_PREFIX_OFFSET, cp, count); for (i = count, dp = cp, f = fp; i; i--, dp++) { - flags = *f++; + if (f) + flags = *f++; switch (flags) { case TTY_NORMAL: gsm->receive(gsm, *dp); diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 1e6405070ce6..8b157d68a03e 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -1244,7 +1244,7 @@ static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, { struct r3964_info *pInfo = tty->disc_data; const unsigned char *p; - char *f, flags = 0; + char *f, flags = TTY_NORMAL; int i; for (i = count, p = cp, f = fp; i; i--, p++) { diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index f15c898ff462..b8347c207cb8 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -84,7 +84,8 @@ * processing. is a pointer to the buffer of input * character received by the device. is a pointer to a * pointer of flag bytes which indicate whether a character was - * received with a parity error, etc. + * received with a parity error, etc. may be NULL to indicate + * all data received is TTY_NORMAL. * * void (*write_wakeup)(struct tty_struct *); * @@ -118,7 +119,8 @@ * processing. is a pointer to the buffer of input * character received by the device. is a pointer to a * pointer of flag bytes which indicate whether a character was - * received with a parity error, etc. + * received with a parity error, etc. may be NULL to indicate + * all data received is TTY_NORMAL. * If assigned, prefer this function for automatic flow control. */ -- cgit v1.2.3-59-g8ed1b From 4d18e6eff81e1d4d81d0942d5b7e96904b3b32df Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Fri, 22 Nov 2013 12:09:55 -0500 Subject: tty: Enable configurable tty flip buffer limit Allow driver to configure its maximum flip buffer memory consumption/limit. This is necessary for very-high speed line rates (in excess of 10MB/sec) because the flip buffers can be saturated before the line discipline has a chance to throttle the input. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 24 +++++++++++++++++++++--- include/linux/tty.h | 1 + include/linux/tty_flip.h | 1 + 3 files changed, 23 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index c043136fbe51..57eb34b2ec24 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -26,7 +26,7 @@ * Byte threshold to limit memory consumption for flip buffers. * The actual memory limit is > 2x this amount. */ -#define TTYB_MEM_LIMIT 65536 +#define TTYB_DEFAULT_MEM_LIMIT 65536 /* * We default to dicing tty buffer allocations to this many characters @@ -89,7 +89,7 @@ void tty_buffer_unlock_exclusive(struct tty_port *port) int tty_buffer_space_avail(struct tty_port *port) { - int space = TTYB_MEM_LIMIT - atomic_read(&port->buf.memory_used); + int space = port->buf.mem_limit - atomic_read(&port->buf.memory_used); return max(space, 0); } @@ -162,7 +162,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size) /* Should possibly check if this fails for the largest buffer we have queued and recycle that ? */ - if (atomic_read(&port->buf.memory_used) > TTYB_MEM_LIMIT) + if (atomic_read(&port->buf.memory_used) > port->buf.mem_limit) return NULL; p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); if (p == NULL) @@ -536,4 +536,22 @@ void tty_buffer_init(struct tty_port *port) atomic_set(&buf->memory_used, 0); atomic_set(&buf->priority, 0); INIT_WORK(&buf->work, flush_to_ldisc); + buf->mem_limit = TTYB_DEFAULT_MEM_LIMIT; } + +/** + * tty_buffer_set_limit - change the tty buffer memory limit + * @port: tty port to change + * + * Change the tty buffer memory limit. + * Must be called before the other tty buffer functions are used. + */ + +int tty_buffer_set_limit(struct tty_port *port, int limit) +{ + if (limit < MIN_TTYB_SIZE) + return -EINVAL; + port->buf.mem_limit = limit; + return 0; +} +EXPORT_SYMBOL_GPL(tty_buffer_set_limit); diff --git a/include/linux/tty.h b/include/linux/tty.h index 97d660ed70c1..2225745060d6 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -61,6 +61,7 @@ struct tty_bufhead { struct tty_buffer sentinel; struct llist_head free; /* Free queue head */ atomic_t memory_used; /* In-use buffers excluding free list */ + int mem_limit; struct tty_buffer *tail; /* Active buffer */ }; /* diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h index 21ddd7d9ea1f..2da8bc2a5486 100644 --- a/include/linux/tty_flip.h +++ b/include/linux/tty_flip.h @@ -1,6 +1,7 @@ #ifndef _LINUX_TTY_FLIP_H #define _LINUX_TTY_FLIP_H +extern int tty_buffer_set_limit(struct tty_port *port, int limit); extern int tty_buffer_space_avail(struct tty_port *port); extern int tty_buffer_request_room(struct tty_port *port, size_t size); extern int tty_insert_flip_string_flags(struct tty_port *port, -- cgit v1.2.3-59-g8ed1b From 5dda4ca5585270c7d6854da5f83e8e8d3e157094 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Fri, 22 Nov 2013 12:09:56 -0500 Subject: tty: Rename tty buffer memory_used field Trim up the memory_used field name to mem_used. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 12 ++++++------ include/linux/tty.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 57eb34b2ec24..e8f22f833b4e 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -89,7 +89,7 @@ void tty_buffer_unlock_exclusive(struct tty_port *port) int tty_buffer_space_avail(struct tty_port *port) { - int space = port->buf.mem_limit - atomic_read(&port->buf.memory_used); + int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used); return max(space, 0); } @@ -129,7 +129,7 @@ void tty_buffer_free_all(struct tty_port *port) buf->head = &buf->sentinel; buf->tail = &buf->sentinel; - atomic_set(&buf->memory_used, 0); + atomic_set(&buf->mem_used, 0); } /** @@ -162,7 +162,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size) /* Should possibly check if this fails for the largest buffer we have queued and recycle that ? */ - if (atomic_read(&port->buf.memory_used) > port->buf.mem_limit) + if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit) return NULL; p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); if (p == NULL) @@ -170,7 +170,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size) found: tty_buffer_reset(p, size); - atomic_add(size, &port->buf.memory_used); + atomic_add(size, &port->buf.mem_used); return p; } @@ -188,7 +188,7 @@ static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b) struct tty_bufhead *buf = &port->buf; /* Dumb strategy for now - should keep some stats */ - WARN_ON(atomic_sub_return(b->size, &buf->memory_used) < 0); + WARN_ON(atomic_sub_return(b->size, &buf->mem_used) < 0); if (b->size > MIN_TTYB_SIZE) kfree(b); @@ -533,7 +533,7 @@ void tty_buffer_init(struct tty_port *port) buf->head = &buf->sentinel; buf->tail = &buf->sentinel; init_llist_head(&buf->free); - atomic_set(&buf->memory_used, 0); + atomic_set(&buf->mem_used, 0); atomic_set(&buf->priority, 0); INIT_WORK(&buf->work, flush_to_ldisc); buf->mem_limit = TTYB_DEFAULT_MEM_LIMIT; diff --git a/include/linux/tty.h b/include/linux/tty.h index 2225745060d6..38fcc0574ba9 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -60,7 +60,7 @@ struct tty_bufhead { atomic_t priority; struct tty_buffer sentinel; struct llist_head free; /* Free queue head */ - atomic_t memory_used; /* In-use buffers excluding free list */ + atomic_t mem_used; /* In-use buffers excluding free list */ int mem_limit; struct tty_buffer *tail; /* Active buffer */ }; -- cgit v1.2.3-59-g8ed1b From 7e1e71d1546a28ea0ccc06320987e6c4ab2e1dbe Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Fri, 22 Nov 2013 12:09:57 -0500 Subject: tty: Remove tty_prepare_flip_string_flags() There is no in-tree user of tty_prepare_flip_string_flags(); remove. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 28 ---------------------------- include/linux/tty_flip.h | 2 -- 2 files changed, 30 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index e8f22f833b4e..6a3620e1cc7a 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -373,34 +373,6 @@ int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, } EXPORT_SYMBOL_GPL(tty_prepare_flip_string); -/** - * tty_prepare_flip_string_flags - make room for characters - * @port: tty port - * @chars: return pointer for character write area - * @flags: return pointer for status flag write area - * @size: desired size - * - * Prepare a block of space in the buffer for data. Returns the length - * available and buffer pointer to the space which is now allocated and - * accounted for as ready for characters. This is used for drivers - * that need their own block copy routines into the buffer. There is no - * guarantee the buffer is a DMA target! - */ - -int tty_prepare_flip_string_flags(struct tty_port *port, - unsigned char **chars, char **flags, size_t size) -{ - int space = tty_buffer_request_room(port, size); - if (likely(space)) { - struct tty_buffer *tb = port->buf.tail; - *chars = char_buf_ptr(tb, tb->used); - *flags = flag_buf_ptr(tb, tb->used); - tb->used += space; - } - return space; -} -EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); - static int receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count) diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h index 2da8bc2a5486..3f821e98af0f 100644 --- a/include/linux/tty_flip.h +++ b/include/linux/tty_flip.h @@ -10,8 +10,6 @@ extern int tty_insert_flip_string_fixed_flag(struct tty_port *port, const unsigned char *chars, char flag, size_t size); extern int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, size_t size); -extern int tty_prepare_flip_string_flags(struct tty_port *port, - unsigned char **chars, char **flags, size_t size); extern void tty_flip_buffer_push(struct tty_port *port); void tty_schedule_flip(struct tty_port *port); -- cgit v1.2.3-59-g8ed1b From 17438217a6f5e33d920ed3821a4b857311cc2872 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 28 Nov 2013 10:41:04 +0100 Subject: serial: pl011: use DMA RX polling by default Making DMA RX polling optional when DMA is on was just over-cautious: there is one single system in the kernel tree using this facility, Ux500 and after some testing I turned this on also for Ux500, which means it should simply be on by default if DMA is enabled. Cc: Jongsung Kim Cc: Chanho Min Cc: Russell King Signed-off-by: Linus Walleij Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 2 +- include/linux/amba/serial.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index a183aceb6d15..c8cc8f02b092 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -325,7 +325,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * dmaengine_slave_config(chan, &rx_conf); uap->dmarx.chan = chan; - if (plat && plat->dma_rx_poll_enable) { + if (plat) { /* Set poll rate if specified. */ if (plat->dma_rx_poll_rate) { uap->dmarx.auto_poll_rate = false; diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h index 0ddb5c02ad8b..0891ea0458f6 100644 --- a/include/linux/amba/serial.h +++ b/include/linux/amba/serial.h @@ -203,7 +203,6 @@ struct amba_pl011_data { bool (*dma_filter)(struct dma_chan *chan, void *filter_param); void *dma_rx_param; void *dma_tx_param; - bool dma_rx_poll_enable; unsigned int dma_rx_poll_rate; unsigned int dma_rx_poll_timeout; void (*init) (void); -- cgit v1.2.3-59-g8ed1b From 9aaf880ed4ee3c3cb1aa628e76c177035ce000ae Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 29 Nov 2013 08:46:32 -0200 Subject: imx-drm: Add mx6 hdmi transmitter support Add mx6 hdmi transmitter support. Original work has been done by Sascha Hauer and Tony Prisk. Special thanks to Russell King for his carefully review, many bug fixes and testing of the mx6 HDMI driver. Tested on the following boards: - mx6q sabresd - mx6dl sabresd - mx6solo wandboard Signed-off-by: Russell King Signed-off-by: Fabio Estevam Signed-off-by: Greg Kroah-Hartman --- drivers/staging/imx-drm/Kconfig | 6 + drivers/staging/imx-drm/Makefile | 1 + drivers/staging/imx-drm/imx-hdmi.c | 1916 +++++++++++++++++++++++++++ drivers/staging/imx-drm/imx-hdmi.h | 1032 +++++++++++++++ include/linux/mfd/syscon/imx6q-iomuxc-gpr.h | 1 + 5 files changed, 2956 insertions(+) create mode 100644 drivers/staging/imx-drm/imx-hdmi.c create mode 100644 drivers/staging/imx-drm/imx-hdmi.h (limited to 'include/linux') diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig index 5032ff7c2259..78319ad176cd 100644 --- a/drivers/staging/imx-drm/Kconfig +++ b/drivers/staging/imx-drm/Kconfig @@ -53,3 +53,9 @@ config DRM_IMX_IPUV3 depends on DRM_IMX_IPUV3_CORE help Choose this if you have a i.MX5 or i.MX6 processor. + +config DRM_IMX_HDMI + tristate "Freescale i.MX DRM HDMI" + depends on DRM_IMX + help + Choose this if you want to use HDMI on i.MX6. diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile index 8742432d7b01..4677585b5ad5 100644 --- a/drivers/staging/imx-drm/Makefile +++ b/drivers/staging/imx-drm/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/ imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o +obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c new file mode 100644 index 000000000000..f3a1f5e2e492 --- /dev/null +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -0,0 +1,1916 @@ +/* + * Copyright (C) 2011-2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * SH-Mobile High-Definition Multimedia Interface (HDMI) driver + * for SLISHDMI13T and SLIPHDMIT IP cores + * + * Copyright (C) 2010, Guennadi Liakhovetski + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ipu-v3/imx-ipu-v3.h" +#include "imx-hdmi.h" +#include "imx-drm.h" + +#define HDMI_EDID_LEN 512 + +#define RGB 0 +#define YCBCR444 1 +#define YCBCR422_16BITS 2 +#define YCBCR422_8BITS 3 +#define XVYCC444 4 + +enum hdmi_datamap { + RGB444_8B = 0x01, + RGB444_10B = 0x03, + RGB444_12B = 0x05, + RGB444_16B = 0x07, + YCbCr444_8B = 0x09, + YCbCr444_10B = 0x0B, + YCbCr444_12B = 0x0D, + YCbCr444_16B = 0x0F, + YCbCr422_8B = 0x16, + YCbCr422_10B = 0x14, + YCbCr422_12B = 0x12, +}; + +enum hdmi_colorimetry { + ITU601, + ITU709, +}; + +enum imx_hdmi_devtype { + IMX6Q_HDMI, + IMX6DL_HDMI, +}; + +static const u16 csc_coeff_default[3][4] = { + { 0x2000, 0x0000, 0x0000, 0x0000 }, + { 0x0000, 0x2000, 0x0000, 0x0000 }, + { 0x0000, 0x0000, 0x2000, 0x0000 } +}; + +static const u16 csc_coeff_rgb_out_eitu601[3][4] = { + { 0x2000, 0x6926, 0x74fd, 0x010e }, + { 0x2000, 0x2cdd, 0x0000, 0x7e9a }, + { 0x2000, 0x0000, 0x38b4, 0x7e3b } +}; + +static const u16 csc_coeff_rgb_out_eitu709[3][4] = { + { 0x2000, 0x7106, 0x7a02, 0x00a7 }, + { 0x2000, 0x3264, 0x0000, 0x7e6d }, + { 0x2000, 0x0000, 0x3b61, 0x7e25 } +}; + +static const u16 csc_coeff_rgb_in_eitu601[3][4] = { + { 0x2591, 0x1322, 0x074b, 0x0000 }, + { 0x6535, 0x2000, 0x7acc, 0x0200 }, + { 0x6acd, 0x7534, 0x2000, 0x0200 } +}; + +static const u16 csc_coeff_rgb_in_eitu709[3][4] = { + { 0x2dc5, 0x0d9b, 0x049e, 0x0000 }, + { 0x62f0, 0x2000, 0x7d11, 0x0200 }, + { 0x6756, 0x78ab, 0x2000, 0x0200 } +}; + +struct hdmi_vmode { + bool mdvi; + bool mhsyncpolarity; + bool mvsyncpolarity; + bool minterlaced; + bool mdataenablepolarity; + + unsigned int mpixelclock; + unsigned int mpixelrepetitioninput; + unsigned int mpixelrepetitionoutput; +}; + +struct hdmi_data_info { + unsigned int enc_in_format; + unsigned int enc_out_format; + unsigned int enc_color_depth; + unsigned int colorimetry; + unsigned int pix_repet_factor; + unsigned int hdcp_enable; + struct hdmi_vmode video_mode; +}; + +struct imx_hdmi { + struct drm_connector connector; + struct imx_drm_connector *imx_drm_connector; + struct drm_encoder encoder; + struct imx_drm_encoder *imx_drm_encoder; + + enum imx_hdmi_devtype dev_type; + struct device *dev; + struct clk *isfr_clk; + struct clk *iahb_clk; + + struct hdmi_data_info hdmi_data; + int vic; + + u8 edid[HDMI_EDID_LEN]; + bool cable_plugin; + + bool phy_enabled; + struct drm_display_mode previous_mode; + + struct regmap *regmap; + struct i2c_adapter *ddc; + void __iomem *regs; + + unsigned long pixel_clk_rate; + unsigned int sample_rate; + int ratio; +}; + +static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di) +{ + regmap_update_bits(hdmi->regmap, IOMUXC_GPR3, + IMX6Q_GPR3_HDMI_MUX_CTL_MASK, + ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT); +} + +static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset) +{ + writeb(val, hdmi->regs + offset); +} + +static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset) +{ + return readb(hdmi->regs + offset); +} + +static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg, + u8 shift, u8 mask) +{ + u8 value = hdmi_readb(hdmi, reg) & ~mask; + value |= (data << shift) & mask; + hdmi_writeb(hdmi, value, reg); +} + +static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi, + unsigned int value) +{ + u8 val; + + hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1); + hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2); + hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3); + + /* nshift factor = 0 */ + val = hdmi_readb(hdmi, HDMI_AUD_CTS3); + val &= ~HDMI_AUD_CTS3_N_SHIFT_MASK; + hdmi_writeb(hdmi, val, HDMI_AUD_CTS3); +} + +static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts) +{ + u8 val; + + /* Must be set/cleared first */ + val = hdmi_readb(hdmi, HDMI_AUD_CTS3); + val &= ~HDMI_AUD_CTS3_CTS_MANUAL; + hdmi_writeb(hdmi, val, HDMI_AUD_CTS3); + + hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); + hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); + hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) | + HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); +} + +static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk, + unsigned int ratio) +{ + unsigned int n = (128 * freq) / 1000; + + switch (freq) { + case 32000: + if (pixel_clk == 25170000) + n = (ratio == 150) ? 9152 : 4576; + else if (pixel_clk == 27020000) + n = (ratio == 150) ? 8192 : 4096; + else if (pixel_clk == 74170000 || pixel_clk == 148350000) + n = 11648; + else + n = 4096; + break; + + case 44100: + if (pixel_clk == 25170000) + n = 7007; + else if (pixel_clk == 74170000) + n = 17836; + else if (pixel_clk == 148350000) + n = (ratio == 150) ? 17836 : 8918; + else + n = 6272; + break; + + case 48000: + if (pixel_clk == 25170000) + n = (ratio == 150) ? 9152 : 6864; + else if (pixel_clk == 27020000) + n = (ratio == 150) ? 8192 : 6144; + else if (pixel_clk == 74170000) + n = 11648; + else if (pixel_clk == 148350000) + n = (ratio == 150) ? 11648 : 5824; + else + n = 6144; + break; + + case 88200: + n = hdmi_compute_n(44100, pixel_clk, ratio) * 2; + break; + + case 96000: + n = hdmi_compute_n(48000, pixel_clk, ratio) * 2; + break; + + case 176400: + n = hdmi_compute_n(44100, pixel_clk, ratio) * 4; + break; + + case 192000: + n = hdmi_compute_n(48000, pixel_clk, ratio) * 4; + break; + + default: + break; + } + + return n; +} + +static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk, + unsigned int ratio) +{ + unsigned int cts = 0; + + pr_debug("%s: freq: %d pixel_clk: %ld ratio: %d\n", __func__, freq, + pixel_clk, ratio); + + switch (freq) { + case 32000: + if (pixel_clk == 297000000) { + cts = 222750; + break; + } + case 48000: + case 96000: + case 192000: + switch (pixel_clk) { + case 25200000: + case 27000000: + case 54000000: + case 74250000: + case 148500000: + cts = pixel_clk / 1000; + break; + case 297000000: + cts = 247500; + break; + /* + * All other TMDS clocks are not supported by + * DWC_hdmi_tx. The TMDS clocks divided or + * multiplied by 1,001 coefficients are not + * supported. + */ + default: + break; + } + break; + case 44100: + case 88200: + case 176400: + switch (pixel_clk) { + case 25200000: + cts = 28000; + break; + case 27000000: + cts = 30000; + break; + case 54000000: + cts = 60000; + break; + case 74250000: + cts = 82500; + break; + case 148500000: + cts = 165000; + break; + case 297000000: + cts = 247500; + break; + default: + break; + } + break; + default: + break; + } + if (ratio == 100) + return cts; + else + return (cts * ratio) / 100; +} + +static void hdmi_get_pixel_clk(struct imx_hdmi *hdmi) +{ + unsigned long rate; + + rate = 65000000; /* FIXME */ + + if (rate) + hdmi->pixel_clk_rate = rate; +} + +static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi) +{ + unsigned int clk_n, clk_cts; + + clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate, + hdmi->ratio); + clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate, + hdmi->ratio); + + if (!clk_cts) { + dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n", + __func__, hdmi->pixel_clk_rate); + return; + } + + dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n", + __func__, hdmi->sample_rate, hdmi->ratio, + hdmi->pixel_clk_rate, clk_n, clk_cts); + + hdmi_set_clock_regenerator_n(hdmi, clk_n); + hdmi_regenerate_cts(hdmi, clk_cts); +} + +static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi) +{ + unsigned int clk_n, clk_cts; + + clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate, + hdmi->ratio); + clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate, + hdmi->ratio); + + if (!clk_cts) { + dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n", + __func__, hdmi->pixel_clk_rate); + return; + } + + dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n", + __func__, hdmi->sample_rate, hdmi->ratio, + hdmi->pixel_clk_rate, clk_n, clk_cts); + + hdmi_set_clock_regenerator_n(hdmi, clk_n); + hdmi_regenerate_cts(hdmi, clk_cts); +} + +static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi) +{ + /* Get pixel clock from ipu */ + hdmi_get_pixel_clk(hdmi); + hdmi_set_clk_regenerator(hdmi); +} + +/* + * this submodule is responsible for the video data synchronization. + * for example, for RGB 4:4:4 input, the data map is defined as + * pin{47~40} <==> R[7:0] + * pin{31~24} <==> G[7:0] + * pin{15~8} <==> B[7:0] + */ +static void hdmi_video_sample(struct imx_hdmi *hdmi) +{ + int color_format = 0; + u8 val; + + if (hdmi->hdmi_data.enc_in_format == RGB) { + if (hdmi->hdmi_data.enc_color_depth == 8) + color_format = 0x01; + else if (hdmi->hdmi_data.enc_color_depth == 10) + color_format = 0x03; + else if (hdmi->hdmi_data.enc_color_depth == 12) + color_format = 0x05; + else if (hdmi->hdmi_data.enc_color_depth == 16) + color_format = 0x07; + else + return; + } else if (hdmi->hdmi_data.enc_in_format == YCBCR444) { + if (hdmi->hdmi_data.enc_color_depth == 8) + color_format = 0x09; + else if (hdmi->hdmi_data.enc_color_depth == 10) + color_format = 0x0B; + else if (hdmi->hdmi_data.enc_color_depth == 12) + color_format = 0x0D; + else if (hdmi->hdmi_data.enc_color_depth == 16) + color_format = 0x0F; + else + return; + } else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) { + if (hdmi->hdmi_data.enc_color_depth == 8) + color_format = 0x16; + else if (hdmi->hdmi_data.enc_color_depth == 10) + color_format = 0x14; + else if (hdmi->hdmi_data.enc_color_depth == 12) + color_format = 0x12; + else + return; + } + + val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE | + ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) & + HDMI_TX_INVID0_VIDEO_MAPPING_MASK); + hdmi_writeb(hdmi, val, HDMI_TX_INVID0); + + /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */ + val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE | + HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE | + HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE; + hdmi_writeb(hdmi, val, HDMI_TX_INSTUFFING); + hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA0); + hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA1); + hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA0); + hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA1); + hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA0); + hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1); +} + +static int is_color_space_conversion(struct imx_hdmi *hdmi) +{ + return (hdmi->hdmi_data.enc_in_format != + hdmi->hdmi_data.enc_out_format); +} + +static int is_color_space_decimation(struct imx_hdmi *hdmi) +{ + return ((hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS) && + (hdmi->hdmi_data.enc_in_format == RGB || + hdmi->hdmi_data.enc_in_format == YCBCR444)); +} + +static int is_color_space_interpolation(struct imx_hdmi *hdmi) +{ + return ((hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) && + (hdmi->hdmi_data.enc_out_format == RGB || + hdmi->hdmi_data.enc_out_format == YCBCR444)); +} + +static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) +{ + const u16 (*csc_coeff)[3][4] = &csc_coeff_default; + u32 csc_scale = 1; + u8 val; + + if (is_color_space_conversion(hdmi)) { + if (hdmi->hdmi_data.enc_out_format == RGB) { + if (hdmi->hdmi_data.colorimetry == ITU601) + csc_coeff = &csc_coeff_rgb_out_eitu601; + else + csc_coeff = &csc_coeff_rgb_out_eitu709; + } else if (hdmi->hdmi_data.enc_in_format == RGB) { + if (hdmi->hdmi_data.colorimetry == ITU601) + csc_coeff = &csc_coeff_rgb_in_eitu601; + else + csc_coeff = &csc_coeff_rgb_in_eitu709; + csc_scale = 0; + } + } + + hdmi_writeb(hdmi, ((*csc_coeff)[0][0] & 0xff), HDMI_CSC_COEF_A1_LSB); + hdmi_writeb(hdmi, ((*csc_coeff)[0][0] >> 8), HDMI_CSC_COEF_A1_MSB); + hdmi_writeb(hdmi, ((*csc_coeff)[0][1] & 0xff), HDMI_CSC_COEF_A2_LSB); + hdmi_writeb(hdmi, ((*csc_coeff)[0][1] >> 8), HDMI_CSC_COEF_A2_MSB); + hdmi_writeb(hdmi, ((*csc_coeff)[0][2] & 0xff), HDMI_CSC_COEF_A3_LSB); + hdmi_writeb(hdmi, ((*csc_coeff)[0][2] >> 8), HDMI_CSC_COEF_A3_MSB); + hdmi_writeb(hdmi, ((*csc_coeff)[0][3] & 0xff), HDMI_CSC_COEF_A4_LSB); + hdmi_writeb(hdmi, ((*csc_coeff)[0][3] >> 8), HDMI_CSC_COEF_A4_MSB); + + hdmi_writeb(hdmi, ((*csc_coeff)[1][0] & 0xff), HDMI_CSC_COEF_B1_LSB); + hdmi_writeb(hdmi, ((*csc_coeff)[1][0] >> 8), HDMI_CSC_COEF_B1_MSB); + hdmi_writeb(hdmi, ((*csc_coeff)[1][1] & 0xff), HDMI_CSC_COEF_B2_LSB); + hdmi_writeb(hdmi, ((*csc_coeff)[1][1] >> 8), HDMI_CSC_COEF_B2_MSB); + hdmi_writeb(hdmi, ((*csc_coeff)[1][2] & 0xff), HDMI_CSC_COEF_B3_LSB); + hdmi_writeb(hdmi, ((*csc_coeff)[1][2] >> 8), HDMI_CSC_COEF_B3_MSB); + hdmi_writeb(hdmi, ((*csc_coeff)[1][3] & 0xff), HDMI_CSC_COEF_B4_LSB); + hdmi_writeb(hdmi, ((*csc_coeff)[1][3] >> 8), HDMI_CSC_COEF_B4_MSB); + + hdmi_writeb(hdmi, ((*csc_coeff)[2][0] & 0xff), HDMI_CSC_COEF_C1_LSB); + hdmi_writeb(hdmi, ((*csc_coeff)[2][0] >> 8), HDMI_CSC_COEF_C1_MSB); + hdmi_writeb(hdmi, ((*csc_coeff)[2][1] & 0xff), HDMI_CSC_COEF_C2_LSB); + hdmi_writeb(hdmi, ((*csc_coeff)[2][1] >> 8), HDMI_CSC_COEF_C2_MSB); + hdmi_writeb(hdmi, ((*csc_coeff)[2][2] & 0xff), HDMI_CSC_COEF_C3_LSB); + hdmi_writeb(hdmi, ((*csc_coeff)[2][2] >> 8), HDMI_CSC_COEF_C3_MSB); + hdmi_writeb(hdmi, ((*csc_coeff)[2][3] & 0xff), HDMI_CSC_COEF_C4_LSB); + hdmi_writeb(hdmi, ((*csc_coeff)[2][3] >> 8), HDMI_CSC_COEF_C4_MSB); + + val = hdmi_readb(hdmi, HDMI_CSC_SCALE); + val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK; + val |= csc_scale & HDMI_CSC_SCALE_CSCSCALE_MASK; + hdmi_writeb(hdmi, val, HDMI_CSC_SCALE); +} + +static void hdmi_video_csc(struct imx_hdmi *hdmi) +{ + int color_depth = 0; + int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE; + int decimation = 0; + u8 val; + + /* YCC422 interpolation to 444 mode */ + if (is_color_space_interpolation(hdmi)) + interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1; + else if (is_color_space_decimation(hdmi)) + decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3; + + if (hdmi->hdmi_data.enc_color_depth == 8) + color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP; + else if (hdmi->hdmi_data.enc_color_depth == 10) + color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP; + else if (hdmi->hdmi_data.enc_color_depth == 12) + color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP; + else if (hdmi->hdmi_data.enc_color_depth == 16) + color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP; + else + return; + + /* Configure the CSC registers */ + hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG); + val = hdmi_readb(hdmi, HDMI_CSC_SCALE); + val &= ~HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK; + val |= color_depth; + hdmi_writeb(hdmi, val, HDMI_CSC_SCALE); + + imx_hdmi_update_csc_coeffs(hdmi); +} + +/* + * HDMI video packetizer is used to packetize the data. + * for example, if input is YCC422 mode or repeater is used, + * data should be repacked this module can be bypassed. + */ +static void hdmi_video_packetize(struct imx_hdmi *hdmi) +{ + unsigned int color_depth = 0; + unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit; + unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP; + struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data; + u8 val; + + if (hdmi_data->enc_out_format == RGB + || hdmi_data->enc_out_format == YCBCR444) { + if (!hdmi_data->enc_color_depth) + output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; + else if (hdmi_data->enc_color_depth == 8) { + color_depth = 4; + output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS; + } else if (hdmi_data->enc_color_depth == 10) + color_depth = 5; + else if (hdmi_data->enc_color_depth == 12) + color_depth = 6; + else if (hdmi_data->enc_color_depth == 16) + color_depth = 7; + else + return; + } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) { + if (!hdmi_data->enc_color_depth || + hdmi_data->enc_color_depth == 8) + remap_size = HDMI_VP_REMAP_YCC422_16bit; + else if (hdmi_data->enc_color_depth == 10) + remap_size = HDMI_VP_REMAP_YCC422_20bit; + else if (hdmi_data->enc_color_depth == 12) + remap_size = HDMI_VP_REMAP_YCC422_24bit; + else + return; + output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422; + } else + return; + + /* set the packetizer registers */ + val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) & + HDMI_VP_PR_CD_COLOR_DEPTH_MASK) | + ((hdmi_data->pix_repet_factor << + HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) & + HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK); + hdmi_writeb(hdmi, val, HDMI_VP_PR_CD); + + val = hdmi_readb(hdmi, HDMI_VP_STUFF); + val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK; + val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE; + hdmi_writeb(hdmi, val, HDMI_VP_STUFF); + + /* Data from pixel repeater block */ + if (hdmi_data->pix_repet_factor > 1) { + val = hdmi_readb(hdmi, HDMI_VP_CONF); + val &= ~(HDMI_VP_CONF_PR_EN_MASK | + HDMI_VP_CONF_BYPASS_SELECT_MASK); + val |= HDMI_VP_CONF_PR_EN_ENABLE | + HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER; + hdmi_writeb(hdmi, val, HDMI_VP_CONF); + } else { /* data from packetizer block */ + val = hdmi_readb(hdmi, HDMI_VP_CONF); + val &= ~(HDMI_VP_CONF_PR_EN_MASK | + HDMI_VP_CONF_BYPASS_SELECT_MASK); + val |= HDMI_VP_CONF_PR_EN_DISABLE | + HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER; + hdmi_writeb(hdmi, val, HDMI_VP_CONF); + } + + val = hdmi_readb(hdmi, HDMI_VP_STUFF); + val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK; + val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET; + hdmi_writeb(hdmi, val, HDMI_VP_STUFF); + + hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP); + + if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) { + val = hdmi_readb(hdmi, HDMI_VP_CONF); + val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | + HDMI_VP_CONF_PP_EN_ENMASK | + HDMI_VP_CONF_YCC422_EN_MASK); + val |= HDMI_VP_CONF_BYPASS_EN_DISABLE | + HDMI_VP_CONF_PP_EN_ENABLE | + HDMI_VP_CONF_YCC422_EN_DISABLE; + hdmi_writeb(hdmi, val, HDMI_VP_CONF); + } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) { + val = hdmi_readb(hdmi, HDMI_VP_CONF); + val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | + HDMI_VP_CONF_PP_EN_ENMASK | + HDMI_VP_CONF_YCC422_EN_MASK); + val |= HDMI_VP_CONF_BYPASS_EN_DISABLE | + HDMI_VP_CONF_PP_EN_DISABLE | + HDMI_VP_CONF_YCC422_EN_ENABLE; + hdmi_writeb(hdmi, val, HDMI_VP_CONF); + } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) { + val = hdmi_readb(hdmi, HDMI_VP_CONF); + val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | + HDMI_VP_CONF_PP_EN_ENMASK | + HDMI_VP_CONF_YCC422_EN_MASK); + val |= HDMI_VP_CONF_BYPASS_EN_ENABLE | + HDMI_VP_CONF_PP_EN_DISABLE | + HDMI_VP_CONF_YCC422_EN_DISABLE; + hdmi_writeb(hdmi, val, HDMI_VP_CONF); + } else { + return; + } + + val = hdmi_readb(hdmi, HDMI_VP_STUFF); + val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK | + HDMI_VP_STUFF_YCC422_STUFFING_MASK); + val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE | + HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE; + hdmi_writeb(hdmi, val, HDMI_VP_STUFF); + + val = hdmi_readb(hdmi, HDMI_VP_CONF); + val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK; + val |= output_select; + hdmi_writeb(hdmi, val, HDMI_VP_CONF); +} + +static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi, + unsigned char bit) +{ + u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0); + val &= ~HDMI_PHY_TST0_TSTCLR_MASK; + val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) & + HDMI_PHY_TST0_TSTCLR_MASK; + hdmi_writeb(hdmi, val, HDMI_PHY_TST0); +} + +static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi, + unsigned char bit) +{ + u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0); + val &= ~HDMI_PHY_TST0_TSTEN_MASK; + val |= (bit << HDMI_PHY_TST0_TSTEN_OFFSET) & + HDMI_PHY_TST0_TSTEN_MASK; + hdmi_writeb(hdmi, val, HDMI_PHY_TST0); +} + +static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi, + unsigned char bit) +{ + u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0); + val &= ~HDMI_PHY_TST0_TSTCLK_MASK; + val |= (bit << HDMI_PHY_TST0_TSTCLK_OFFSET) & + HDMI_PHY_TST0_TSTCLK_MASK; + hdmi_writeb(hdmi, val, HDMI_PHY_TST0); +} + +static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi, + unsigned char bit) +{ + hdmi_writeb(hdmi, bit, HDMI_PHY_TST1); +} + +static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi, + unsigned char bit) +{ + hdmi_writeb(hdmi, bit, HDMI_PHY_TST2); +} + +static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec) +{ + unsigned char val = 0; + val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3; + while (!val) { + udelay(1000); + if (msec-- == 0) + return false; + val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3; + } + return true; +} + +static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data, + unsigned char addr) +{ + hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0); + hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR); + hdmi_writeb(hdmi, (unsigned char)(data >> 8), + HDMI_PHY_I2CM_DATAO_1_ADDR); + hdmi_writeb(hdmi, (unsigned char)(data >> 0), + HDMI_PHY_I2CM_DATAO_0_ADDR); + hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE, + HDMI_PHY_I2CM_OPERATION_ADDR); + hdmi_phy_wait_i2c_done(hdmi, 1000); +} + +static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data, + unsigned char addr) +{ + __hdmi_phy_i2c_write(hdmi, data, addr); + return 0; +} + +static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable) +{ + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, + HDMI_PHY_CONF0_PDZ_OFFSET, + HDMI_PHY_CONF0_PDZ_MASK); +} + +static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable) +{ + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, + HDMI_PHY_CONF0_ENTMDS_OFFSET, + HDMI_PHY_CONF0_ENTMDS_MASK); +} + +static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable) +{ + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, + HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET, + HDMI_PHY_CONF0_GEN2_PDDQ_MASK); +} + +static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable) +{ + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, + HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET, + HDMI_PHY_CONF0_GEN2_TXPWRON_MASK); +} + +static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable) +{ + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, + HDMI_PHY_CONF0_SELDATAENPOL_OFFSET, + HDMI_PHY_CONF0_SELDATAENPOL_MASK); +} + +static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable) +{ + hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0, + HDMI_PHY_CONF0_SELDIPIF_OFFSET, + HDMI_PHY_CONF0_SELDIPIF_MASK); +} + +static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, + unsigned char res, int cscon) +{ + u8 val, msec; + + /* color resolution 0 is 8 bit colour depth */ + if (!res) + res = 8; + + if (prep) + return -EINVAL; + else if (res != 8 && res != 12) + return -EINVAL; + + /* Enable csc path */ + if (cscon) + val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH; + else + val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS; + + hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL); + + /* gen2 tx power off */ + imx_hdmi_phy_gen2_txpwron(hdmi, 0); + + /* gen2 pddq */ + imx_hdmi_phy_gen2_pddq(hdmi, 1); + + /* PHY reset */ + hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ); + hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ); + + hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST); + + hdmi_phy_test_clear(hdmi, 1); + hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2, + HDMI_PHY_I2CM_SLAVE_ADDR); + hdmi_phy_test_clear(hdmi, 0); + + if (hdmi->hdmi_data.video_mode.mpixelclock <= 45250000) { + switch (res) { + case 8: + /* PLL/MPLL Cfg */ + hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06); + hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); /* GMPCTRL */ + break; + case 10: + hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06); + hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); + break; + case 12: + hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06); + hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); + break; + default: + return -EINVAL; + } + } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 92500000) { + switch (res) { + case 8: + hdmi_phy_i2c_write(hdmi, 0x0140, 0x06); + hdmi_phy_i2c_write(hdmi, 0x0005, 0x15); + break; + case 10: + hdmi_phy_i2c_write(hdmi, 0x2141, 0x06); + hdmi_phy_i2c_write(hdmi, 0x0005, 0x15); + break; + case 12: + hdmi_phy_i2c_write(hdmi, 0x4142, 0x06); + hdmi_phy_i2c_write(hdmi, 0x0005, 0x15); + default: + return -EINVAL; + } + } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 148500000) { + switch (res) { + case 8: + hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06); + hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); + break; + case 10: + hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06); + hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); + break; + case 12: + hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06); + hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); + default: + return -EINVAL; + } + } else { + switch (res) { + case 8: + hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06); + hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); + break; + case 10: + hdmi_phy_i2c_write(hdmi, 0x2001, 0x06); + hdmi_phy_i2c_write(hdmi, 0x000f, 0x15); + break; + case 12: + hdmi_phy_i2c_write(hdmi, 0x4002, 0x06); + hdmi_phy_i2c_write(hdmi, 0x000f, 0x15); + default: + return -EINVAL; + } + } + + if (hdmi->hdmi_data.video_mode.mpixelclock <= 54000000) { + switch (res) { + case 8: + hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); /* CURRCTRL */ + break; + case 10: + hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); + break; + case 12: + hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); + break; + default: + return -EINVAL; + } + } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 58400000) { + switch (res) { + case 8: + hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); + break; + case 10: + hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); + break; + case 12: + hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); + break; + default: + return -EINVAL; + } + } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 72000000) { + switch (res) { + case 8: + hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); + break; + case 10: + hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); + break; + case 12: + hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); + break; + default: + return -EINVAL; + } + } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 74250000) { + switch (res) { + case 8: + hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); + break; + case 10: + hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10); + break; + case 12: + hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); + break; + default: + return -EINVAL; + } + } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 118800000) { + switch (res) { + case 8: + hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); + break; + case 10: + hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); + break; + case 12: + hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); + break; + default: + return -EINVAL; + } + } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 216000000) { + switch (res) { + case 8: + hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); + break; + case 10: + hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10); + break; + case 12: + hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); + break; + default: + return -EINVAL; + } + } else { + dev_err(hdmi->dev, + "Pixel clock %d - unsupported by HDMI\n", + hdmi->hdmi_data.video_mode.mpixelclock); + return -EINVAL; + } + + hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ + hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); + /* RESISTANCE TERM 133Ohm Cfg */ + hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */ + /* PREEMP Cgf 0.00 */ + hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */ + /* TX/CK LVL 10 */ + hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */ + /* REMOVE CLK TERM */ + hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */ + + imx_hdmi_phy_enable_power(hdmi, 1); + + /* toggle TMDS enable */ + imx_hdmi_phy_enable_tmds(hdmi, 0); + imx_hdmi_phy_enable_tmds(hdmi, 1); + + /* gen2 tx power on */ + imx_hdmi_phy_gen2_txpwron(hdmi, 1); + imx_hdmi_phy_gen2_pddq(hdmi, 0); + + /*Wait for PHY PLL lock */ + msec = 5; + do { + val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK; + if (!val) + break; + + if (msec == 0) { + dev_err(hdmi->dev, "PHY PLL not locked\n"); + return -ETIMEDOUT; + } + + udelay(1000); + msec--; + } while (1); + + return 0; +} + +static int imx_hdmi_phy_init(struct imx_hdmi *hdmi) +{ + int i, ret; + bool cscon = false; + + /*check csc whether needed activated in HDMI mode */ + cscon = (is_color_space_conversion(hdmi) && + !hdmi->hdmi_data.video_mode.mdvi); + + /* HDMI Phy spec says to do the phy initialization sequence twice */ + for (i = 0; i < 2; i++) { + imx_hdmi_phy_sel_data_en_pol(hdmi, 1); + imx_hdmi_phy_sel_interface_control(hdmi, 0); + imx_hdmi_phy_enable_tmds(hdmi, 0); + imx_hdmi_phy_enable_power(hdmi, 0); + + /* Enable CSC */ + ret = hdmi_phy_configure(hdmi, 0, 8, cscon); + if (ret) + return ret; + } + + hdmi->phy_enabled = true; + return 0; +} + +static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi) +{ + u8 de, val; + + if (hdmi->hdmi_data.video_mode.mdataenablepolarity) + de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH; + else + de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW; + + /* disable rx detect */ + val = hdmi_readb(hdmi, HDMI_A_HDCPCFG0); + val &= HDMI_A_HDCPCFG0_RXDETECT_MASK; + val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE; + hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG0); + + val = hdmi_readb(hdmi, HDMI_A_VIDPOLCFG); + val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK; + val |= de; + hdmi_writeb(hdmi, val, HDMI_A_VIDPOLCFG); + + val = hdmi_readb(hdmi, HDMI_A_HDCPCFG1); + val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK; + val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE; + hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG1); +} + +static void hdmi_config_AVI(struct imx_hdmi *hdmi) +{ + u8 val, pix_fmt, under_scan; + u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry; + bool aspect_16_9; + + aspect_16_9 = false; /* FIXME */ + + /* AVI Data Byte 1 */ + if (hdmi->hdmi_data.enc_out_format == YCBCR444) + pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR444; + else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS) + pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR422; + else + pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_RGB; + + under_scan = HDMI_FC_AVICONF0_SCAN_INFO_NODATA; + + /* + * Active format identification data is present in the AVI InfoFrame. + * Under scan info, no bar data + */ + val = pix_fmt | under_scan | + HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT | + HDMI_FC_AVICONF0_BAR_DATA_NO_DATA; + + hdmi_writeb(hdmi, val, HDMI_FC_AVICONF0); + + /* AVI Data Byte 2 -Set the Aspect Ratio */ + if (aspect_16_9) { + act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9; + coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9; + } else { + act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3; + coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3; + } + + /* Set up colorimetry */ + if (hdmi->hdmi_data.enc_out_format == XVYCC444) { + colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO; + if (hdmi->hdmi_data.colorimetry == ITU601) + ext_colorimetry = + HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601; + else /* hdmi->hdmi_data.colorimetry == ITU709 */ + ext_colorimetry = + HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709; + } else if (hdmi->hdmi_data.enc_out_format != RGB) { + if (hdmi->hdmi_data.colorimetry == ITU601) + colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE; + else /* hdmi->hdmi_data.colorimetry == ITU709 */ + colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR; + ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601; + } else { /* Carries no data */ + colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA; + ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601; + } + + val = colorimetry | coded_ratio | act_ratio; + hdmi_writeb(hdmi, val, HDMI_FC_AVICONF1); + + /* AVI Data Byte 3 */ + val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry | + HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT | + HDMI_FC_AVICONF2_SCALING_NONE; + hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2); + + /* AVI Data Byte 4 */ + hdmi_writeb(hdmi, hdmi->vic, HDMI_FC_AVIVID); + + /* AVI Data Byte 5- set up input and output pixel repetition */ + val = (((hdmi->hdmi_data.video_mode.mpixelrepetitioninput + 1) << + HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) & + HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) | + ((hdmi->hdmi_data.video_mode.mpixelrepetitionoutput << + HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) & + HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK); + hdmi_writeb(hdmi, val, HDMI_FC_PRCONF); + + /* IT Content and quantization range = don't care */ + val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS | + HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED; + hdmi_writeb(hdmi, val, HDMI_FC_AVICONF3); + + /* AVI Data Bytes 6-13 */ + hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB0); + hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB1); + hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB0); + hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB1); + hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB0); + hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB1); + hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB0); + hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1); +} + +static void hdmi_av_composer(struct imx_hdmi *hdmi, + const struct drm_display_mode *mode) +{ + u8 inv_val; + struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode; + int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; + + vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC); + vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC); + vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); + vmode->mpixelclock = mode->clock * 1000; + + dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock); + + /* Set up HDMI_FC_INVIDCONF */ + inv_val = (hdmi->hdmi_data.hdcp_enable ? + HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE : + HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE); + + inv_val |= (vmode->mvsyncpolarity ? + HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH : + HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW); + + inv_val |= (vmode->mhsyncpolarity ? + HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH : + HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW); + + inv_val |= (vmode->mdataenablepolarity ? + HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH : + HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW); + + if (hdmi->vic == 39) + inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH; + else + inv_val |= (vmode->minterlaced ? + HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH : + HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW); + + inv_val |= (vmode->minterlaced ? + HDMI_FC_INVIDCONF_IN_I_P_INTERLACED : + HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE); + + inv_val |= (vmode->mdvi ? + HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE : + HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE); + + hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF); + + /* Set up horizontal active pixel width */ + hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1); + hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0); + + /* Set up vertical active lines */ + hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1); + hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0); + + /* Set up horizontal blanking pixel region width */ + hblank = mode->htotal - mode->hdisplay; + hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1); + hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0); + + /* Set up vertical blanking pixel region width */ + vblank = mode->vtotal - mode->vdisplay; + hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK); + + /* Set up HSYNC active edge delay width (in pixel clks) */ + h_de_hs = mode->hsync_start - mode->hdisplay; + hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1); + hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0); + + /* Set up VSYNC active edge delay (in lines) */ + v_de_vs = mode->vsync_start - mode->vdisplay; + hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY); + + /* Set up HSYNC active pulse width (in pixel clks) */ + hsync_len = mode->hsync_end - mode->hsync_start; + hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1); + hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0); + + /* Set up VSYNC active edge delay (in lines) */ + vsync_len = mode->vsync_end - mode->vsync_start; + hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH); +} + +static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi) +{ + if (!hdmi->phy_enabled) + return; + + imx_hdmi_phy_enable_tmds(hdmi, 0); + imx_hdmi_phy_enable_power(hdmi, 0); + + hdmi->phy_enabled = false; +} + +/* HDMI Initialization Step B.4 */ +static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi) +{ + u8 clkdis; + + /* control period minimum duration */ + hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR); + hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR); + hdmi_writeb(hdmi, 1, HDMI_FC_EXCTRLSPAC); + + /* Set to fill TMDS data channels */ + hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM); + hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM); + hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM); + + /* Enable pixel clock and tmds data path */ + clkdis = 0x7F; + clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE; + hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + + clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE; + hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + + /* Enable csc path */ + if (is_color_space_conversion(hdmi)) { + clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE; + hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + } +} + +static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi) +{ + u8 clkdis; + + clkdis = hdmi_readb(hdmi, HDMI_MC_CLKDIS); + clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE; + hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); +} + +/* Workaround to clear the overflow condition */ +static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi) +{ + int count; + u8 val; + + /* TMDS software reset */ + hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ); + + val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF); + if (hdmi->dev_type == IMX6DL_HDMI) { + hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF); + return; + } + + for (count = 0; count < 4; count++) + hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF); +} + +static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi) +{ + hdmi_writeb(hdmi, 0, HDMI_FC_MASK2); + hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2); +} + +static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi) +{ + hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK, + HDMI_IH_MUTE_FC_STAT2); +} + +static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) +{ + int ret; + + hdmi_disable_overflow_interrupts(hdmi); + + hdmi->vic = drm_match_cea_mode(mode); + + if (!hdmi->vic) { + dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n"); + hdmi->hdmi_data.video_mode.mdvi = true; + } else { + dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic); + hdmi->hdmi_data.video_mode.mdvi = false; + } + + if ((hdmi->vic == 6) || (hdmi->vic == 7) || + (hdmi->vic == 21) || (hdmi->vic == 22) || + (hdmi->vic == 2) || (hdmi->vic == 3) || + (hdmi->vic == 17) || (hdmi->vic == 18)) + hdmi->hdmi_data.colorimetry = ITU601; + else + hdmi->hdmi_data.colorimetry = ITU709; + + if ((hdmi->vic == 10) || (hdmi->vic == 11) || + (hdmi->vic == 12) || (hdmi->vic == 13) || + (hdmi->vic == 14) || (hdmi->vic == 15) || + (hdmi->vic == 25) || (hdmi->vic == 26) || + (hdmi->vic == 27) || (hdmi->vic == 28) || + (hdmi->vic == 29) || (hdmi->vic == 30) || + (hdmi->vic == 35) || (hdmi->vic == 36) || + (hdmi->vic == 37) || (hdmi->vic == 38)) + hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1; + else + hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0; + + hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0; + + /* TODO: Get input format from IPU (via FB driver interface) */ + hdmi->hdmi_data.enc_in_format = RGB; + + hdmi->hdmi_data.enc_out_format = RGB; + + hdmi->hdmi_data.enc_color_depth = 8; + hdmi->hdmi_data.pix_repet_factor = 0; + hdmi->hdmi_data.hdcp_enable = 0; + hdmi->hdmi_data.video_mode.mdataenablepolarity = true; + + /* HDMI Initialization Step B.1 */ + hdmi_av_composer(hdmi, mode); + + /* HDMI Initializateion Step B.2 */ + ret = imx_hdmi_phy_init(hdmi); + if (ret) + return ret; + + /* HDMI Initialization Step B.3 */ + imx_hdmi_enable_video_path(hdmi); + + /* not for DVI mode */ + if (hdmi->hdmi_data.video_mode.mdvi) + dev_dbg(hdmi->dev, "%s DVI mode\n", __func__); + else { + dev_dbg(hdmi->dev, "%s CEA mode\n", __func__); + + /* HDMI Initialization Step E - Configure audio */ + hdmi_clk_regenerator_update_pixel_clock(hdmi); + hdmi_enable_audio_clk(hdmi); + + /* HDMI Initialization Step F - Configure AVI InfoFrame */ + hdmi_config_AVI(hdmi); + } + + hdmi_video_packetize(hdmi); + hdmi_video_csc(hdmi); + hdmi_video_sample(hdmi); + hdmi_tx_hdcp_config(hdmi); + + imx_hdmi_clear_overflow(hdmi); + if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi) + hdmi_enable_overflow_interrupts(hdmi); + + return 0; +} + +/* Wait until we are registered to enable interrupts */ +static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi) +{ + hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL, + HDMI_PHY_I2CM_INT_ADDR); + + hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL | + HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL, + HDMI_PHY_I2CM_CTLINT_ADDR); + + /* enable cable hot plug irq */ + hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0); + + /* Clear Hotplug interrupts */ + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); + + /* Unmute interrupts */ + hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); + + return 0; +} + +static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi) +{ + u8 ih_mute; + + /* + * Boot up defaults are: + * HDMI_IH_MUTE = 0x03 (disabled) + * HDMI_IH_MUTE_* = 0x00 (enabled) + * + * Disable top level interrupt bits in HDMI block + */ + ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) | + HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT | + HDMI_IH_MUTE_MUTE_ALL_INTERRUPT; + + hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE); + + /* by default mask all interrupts */ + hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK); + hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0); + hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1); + hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK2); + hdmi_writeb(hdmi, 0xff, HDMI_PHY_MASK0); + hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR); + hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR); + hdmi_writeb(hdmi, 0xff, HDMI_AUD_INT); + hdmi_writeb(hdmi, 0xff, HDMI_AUD_SPDIFINT); + hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK); + hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK); + hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK); + hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK); + hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT); + hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT); + + /* Disable interrupts in the IH_MUTE_* registers */ + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0); + hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0); + + /* Enable top level interrupt bits in HDMI block */ + ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT | + HDMI_IH_MUTE_MUTE_ALL_INTERRUPT); + hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE); +} + +static void imx_hdmi_poweron(struct imx_hdmi *hdmi) +{ + imx_hdmi_setup(hdmi, &hdmi->previous_mode); +} + +static void imx_hdmi_poweroff(struct imx_hdmi *hdmi) +{ + imx_hdmi_phy_disable(hdmi); +} + +static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector + *connector, bool force) +{ + /* FIXME */ + return connector_status_connected; +} + +static void imx_hdmi_connector_destroy(struct drm_connector *connector) +{ +} + +static int imx_hdmi_connector_get_modes(struct drm_connector *connector) +{ + struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, + connector); + struct edid *edid; + int ret; + + if (!hdmi->ddc) + return 0; + + edid = drm_get_edid(connector, hdmi->ddc); + if (edid) { + dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n", + edid->width_cm, edid->height_cm); + + drm_mode_connector_update_edid_property(connector, edid); + ret = drm_add_edid_modes(connector, edid); + kfree(edid); + } else { + dev_dbg(hdmi->dev, "failed to get edid\n"); + } + + return 0; +} + +static int imx_hdmi_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + + return MODE_OK; +} + +static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector + *connector) +{ + struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, + connector); + + return &hdmi->encoder; +} + +static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); + + imx_hdmi_setup(hdmi, mode); + + /* Store the display mode for plugin/DKMS poweron events */ + memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode)); +} + +static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void imx_hdmi_encoder_disable(struct drm_encoder *encoder) +{ +} + +static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); + + if (mode) + imx_hdmi_poweroff(hdmi); + else + imx_hdmi_poweron(hdmi); +} + +static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder) +{ + struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); + + imx_hdmi_poweroff(hdmi); + imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE, + V4L2_PIX_FMT_RGB24); +} + +static void imx_hdmi_encoder_commit(struct drm_encoder *encoder) +{ + struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); + int mux = imx_drm_encoder_get_mux_id(hdmi->imx_drm_encoder, + encoder->crtc); + + imx_hdmi_set_ipu_di_mux(hdmi, mux); + + imx_hdmi_poweron(hdmi); +} + +static void imx_hdmi_encoder_destroy(struct drm_encoder *encoder) +{ + return; +} + +static struct drm_encoder_funcs imx_hdmi_encoder_funcs = { + .destroy = imx_hdmi_encoder_destroy, +}; + +static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = { + .dpms = imx_hdmi_encoder_dpms, + .prepare = imx_hdmi_encoder_prepare, + .commit = imx_hdmi_encoder_commit, + .mode_set = imx_hdmi_encoder_mode_set, + .mode_fixup = imx_hdmi_encoder_mode_fixup, + .disable = imx_hdmi_encoder_disable, +}; + +static struct drm_connector_funcs imx_hdmi_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = imx_hdmi_connector_detect, + .destroy = imx_hdmi_connector_destroy, +}; + +static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = { + .get_modes = imx_hdmi_connector_get_modes, + .mode_valid = imx_hdmi_connector_mode_valid, + .best_encoder = imx_hdmi_connector_best_encoder, +}; + +static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) +{ + struct imx_hdmi *hdmi = dev_id; + u8 intr_stat; + u8 phy_int_pol; + u8 val; + + intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0); + + phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0); + + if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { + if (phy_int_pol & HDMI_PHY_HPD) { + dev_dbg(hdmi->dev, "EVENT=plugin\n"); + + val = hdmi_readb(hdmi, HDMI_PHY_POL0); + val &= ~HDMI_PHY_HPD; + hdmi_writeb(hdmi, val, HDMI_PHY_POL0); + + imx_hdmi_poweron(hdmi); + } else { + dev_dbg(hdmi->dev, "EVENT=plugout\n"); + + val = hdmi_readb(hdmi, HDMI_PHY_POL0); + val |= HDMI_PHY_HPD; + hdmi_writeb(hdmi, val, HDMI_PHY_POL0); + + imx_hdmi_poweroff(hdmi); + } + } + + hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); + + return IRQ_HANDLED; +} + +static int imx_hdmi_register(struct imx_hdmi *hdmi) +{ + int ret; + + hdmi->connector.funcs = &imx_hdmi_connector_funcs; + hdmi->encoder.funcs = &imx_hdmi_encoder_funcs; + + hdmi->encoder.encoder_type = DRM_MODE_ENCODER_TMDS; + hdmi->connector.connector_type = DRM_MODE_CONNECTOR_HDMIA; + + drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs); + ret = imx_drm_add_encoder(&hdmi->encoder, &hdmi->imx_drm_encoder, + THIS_MODULE); + if (ret) { + dev_err(hdmi->dev, "adding encoder failed: %d\n", ret); + return ret; + } + + drm_connector_helper_add(&hdmi->connector, + &imx_hdmi_connector_helper_funcs); + + ret = imx_drm_add_connector(&hdmi->connector, + &hdmi->imx_drm_connector, THIS_MODULE); + if (ret) { + imx_drm_remove_encoder(hdmi->imx_drm_encoder); + dev_err(hdmi->dev, "adding connector failed: %d\n", ret); + return ret; + } + + hdmi->connector.encoder = &hdmi->encoder; + + drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder); + + return 0; +} + +static struct platform_device_id imx_hdmi_devtype[] = { + { + .name = "imx6q-hdmi", + .driver_data = IMX6Q_HDMI, + }, { + .name = "imx6dl-hdmi", + .driver_data = IMX6DL_HDMI, + }, { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype); + +static const struct of_device_id imx_hdmi_dt_ids[] = { +{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], }, +{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], }, +{ /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids); + +static int imx_hdmi_platform_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(imx_hdmi_dt_ids, &pdev->dev); + struct device_node *np = pdev->dev.of_node; + struct device_node *ddc_node; + struct imx_hdmi *hdmi; + struct resource *iores; + int ret, irq; + + hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + if (!hdmi) + return -ENOMEM; + + hdmi->dev = &pdev->dev; + + if (of_id) { + const struct platform_device_id *device_id = of_id->data; + hdmi->dev_type = device_id->driver_data; + } + + ddc_node = of_parse_phandle(np, "ddc", 0); + if (ddc_node) { + hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node); + if (!hdmi->ddc) + dev_dbg(hdmi->dev, "failed to read ddc node\n"); + + of_node_put(ddc_node); + } else { + dev_dbg(hdmi->dev, "no ddc property found\n"); + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -EINVAL; + + ret = devm_request_irq(&pdev->dev, irq, imx_hdmi_irq, 0, + dev_name(&pdev->dev), hdmi); + if (ret) + return ret; + + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hdmi->regs = devm_ioremap_resource(&pdev->dev, iores); + if (IS_ERR(hdmi->regs)) + return PTR_ERR(hdmi->regs); + + hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); + if (IS_ERR(hdmi->regmap)) + return PTR_ERR(hdmi->regmap); + + hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr"); + if (IS_ERR(hdmi->isfr_clk)) { + ret = PTR_ERR(hdmi->isfr_clk); + dev_err(hdmi->dev, + "Unable to get HDMI isfr clk: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(hdmi->isfr_clk); + if (ret) { + dev_err(hdmi->dev, + "Cannot enable HDMI isfr clock: %d\n", ret); + return ret; + } + + hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb"); + if (IS_ERR(hdmi->iahb_clk)) { + ret = PTR_ERR(hdmi->iahb_clk); + dev_err(hdmi->dev, + "Unable to get HDMI iahb clk: %d\n", ret); + goto err_isfr; + } + + ret = clk_prepare_enable(hdmi->iahb_clk); + if (ret) { + dev_err(hdmi->dev, + "Cannot enable HDMI iahb clock: %d\n", ret); + goto err_isfr; + } + + /* Product and revision IDs */ + dev_info(&pdev->dev, + "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", + hdmi_readb(hdmi, HDMI_DESIGN_ID), + hdmi_readb(hdmi, HDMI_REVISION_ID), + hdmi_readb(hdmi, HDMI_PRODUCT_ID0), + hdmi_readb(hdmi, HDMI_PRODUCT_ID1)); + + initialize_hdmi_ih_mutes(hdmi); + + /* + * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator + * N and cts values before enabling phy + */ + hdmi_init_clk_regenerator(hdmi); + + /* + * Configure registers related to HDMI interrupt + * generation before registering IRQ. + */ + hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0); + + /* Clear Hotplug interrupts */ + hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); + + ret = imx_hdmi_fb_registered(hdmi); + if (ret) + goto err_iahb; + + ret = imx_hdmi_register(hdmi); + if (ret) + goto err_iahb; + + imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np); + + platform_set_drvdata(pdev, hdmi); + + return 0; + +err_iahb: + clk_disable_unprepare(hdmi->iahb_clk); +err_isfr: + clk_disable_unprepare(hdmi->isfr_clk); + + return ret; +} + +static int imx_hdmi_platform_remove(struct platform_device *pdev) +{ + struct imx_hdmi *hdmi = platform_get_drvdata(pdev); + struct drm_connector *connector = &hdmi->connector; + struct drm_encoder *encoder = &hdmi->encoder; + + drm_mode_connector_detach_encoder(connector, encoder); + imx_drm_remove_connector(hdmi->imx_drm_connector); + imx_drm_remove_encoder(hdmi->imx_drm_encoder); + + clk_disable_unprepare(hdmi->iahb_clk); + clk_disable_unprepare(hdmi->isfr_clk); + i2c_put_adapter(hdmi->ddc); + + return 0; +} + +static struct platform_driver imx_hdmi_driver = { + .probe = imx_hdmi_platform_probe, + .remove = imx_hdmi_platform_remove, + .driver = { + .name = "imx-hdmi", + .owner = THIS_MODULE, + .of_match_table = imx_hdmi_dt_ids, + }, +}; + +module_platform_driver(imx_hdmi_driver); + +MODULE_AUTHOR("Sascha Hauer "); +MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:imx-hdmi"); diff --git a/drivers/staging/imx-drm/imx-hdmi.h b/drivers/staging/imx-drm/imx-hdmi.h new file mode 100644 index 000000000000..39b677689db6 --- /dev/null +++ b/drivers/staging/imx-drm/imx-hdmi.h @@ -0,0 +1,1032 @@ +/* + * Copyright (C) 2011 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __IMX_HDMI_H__ +#define __IMX_HDMI_H__ + +/* Identification Registers */ +#define HDMI_DESIGN_ID 0x0000 +#define HDMI_REVISION_ID 0x0001 +#define HDMI_PRODUCT_ID0 0x0002 +#define HDMI_PRODUCT_ID1 0x0003 +#define HDMI_CONFIG0_ID 0x0004 +#define HDMI_CONFIG1_ID 0x0005 +#define HDMI_CONFIG2_ID 0x0006 +#define HDMI_CONFIG3_ID 0x0007 + +/* Interrupt Registers */ +#define HDMI_IH_FC_STAT0 0x0100 +#define HDMI_IH_FC_STAT1 0x0101 +#define HDMI_IH_FC_STAT2 0x0102 +#define HDMI_IH_AS_STAT0 0x0103 +#define HDMI_IH_PHY_STAT0 0x0104 +#define HDMI_IH_I2CM_STAT0 0x0105 +#define HDMI_IH_CEC_STAT0 0x0106 +#define HDMI_IH_VP_STAT0 0x0107 +#define HDMI_IH_I2CMPHY_STAT0 0x0108 +#define HDMI_IH_AHBDMAAUD_STAT0 0x0109 + +#define HDMI_IH_MUTE_FC_STAT0 0x0180 +#define HDMI_IH_MUTE_FC_STAT1 0x0181 +#define HDMI_IH_MUTE_FC_STAT2 0x0182 +#define HDMI_IH_MUTE_AS_STAT0 0x0183 +#define HDMI_IH_MUTE_PHY_STAT0 0x0184 +#define HDMI_IH_MUTE_I2CM_STAT0 0x0185 +#define HDMI_IH_MUTE_CEC_STAT0 0x0186 +#define HDMI_IH_MUTE_VP_STAT0 0x0187 +#define HDMI_IH_MUTE_I2CMPHY_STAT0 0x0188 +#define HDMI_IH_MUTE_AHBDMAAUD_STAT0 0x0189 +#define HDMI_IH_MUTE 0x01FF + +/* Video Sample Registers */ +#define HDMI_TX_INVID0 0x0200 +#define HDMI_TX_INSTUFFING 0x0201 +#define HDMI_TX_GYDATA0 0x0202 +#define HDMI_TX_GYDATA1 0x0203 +#define HDMI_TX_RCRDATA0 0x0204 +#define HDMI_TX_RCRDATA1 0x0205 +#define HDMI_TX_BCBDATA0 0x0206 +#define HDMI_TX_BCBDATA1 0x0207 + +/* Video Packetizer Registers */ +#define HDMI_VP_STATUS 0x0800 +#define HDMI_VP_PR_CD 0x0801 +#define HDMI_VP_STUFF 0x0802 +#define HDMI_VP_REMAP 0x0803 +#define HDMI_VP_CONF 0x0804 +#define HDMI_VP_STAT 0x0805 +#define HDMI_VP_INT 0x0806 +#define HDMI_VP_MASK 0x0807 +#define HDMI_VP_POL 0x0808 + +/* Frame Composer Registers */ +#define HDMI_FC_INVIDCONF 0x1000 +#define HDMI_FC_INHACTV0 0x1001 +#define HDMI_FC_INHACTV1 0x1002 +#define HDMI_FC_INHBLANK0 0x1003 +#define HDMI_FC_INHBLANK1 0x1004 +#define HDMI_FC_INVACTV0 0x1005 +#define HDMI_FC_INVACTV1 0x1006 +#define HDMI_FC_INVBLANK 0x1007 +#define HDMI_FC_HSYNCINDELAY0 0x1008 +#define HDMI_FC_HSYNCINDELAY1 0x1009 +#define HDMI_FC_HSYNCINWIDTH0 0x100A +#define HDMI_FC_HSYNCINWIDTH1 0x100B +#define HDMI_FC_VSYNCINDELAY 0x100C +#define HDMI_FC_VSYNCINWIDTH 0x100D +#define HDMI_FC_INFREQ0 0x100E +#define HDMI_FC_INFREQ1 0x100F +#define HDMI_FC_INFREQ2 0x1010 +#define HDMI_FC_CTRLDUR 0x1011 +#define HDMI_FC_EXCTRLDUR 0x1012 +#define HDMI_FC_EXCTRLSPAC 0x1013 +#define HDMI_FC_CH0PREAM 0x1014 +#define HDMI_FC_CH1PREAM 0x1015 +#define HDMI_FC_CH2PREAM 0x1016 +#define HDMI_FC_AVICONF3 0x1017 +#define HDMI_FC_GCP 0x1018 +#define HDMI_FC_AVICONF0 0x1019 +#define HDMI_FC_AVICONF1 0x101A +#define HDMI_FC_AVICONF2 0x101B +#define HDMI_FC_AVIVID 0x101C +#define HDMI_FC_AVIETB0 0x101D +#define HDMI_FC_AVIETB1 0x101E +#define HDMI_FC_AVISBB0 0x101F +#define HDMI_FC_AVISBB1 0x1020 +#define HDMI_FC_AVIELB0 0x1021 +#define HDMI_FC_AVIELB1 0x1022 +#define HDMI_FC_AVISRB0 0x1023 +#define HDMI_FC_AVISRB1 0x1024 +#define HDMI_FC_AUDICONF0 0x1025 +#define HDMI_FC_AUDICONF1 0x1026 +#define HDMI_FC_AUDICONF2 0x1027 +#define HDMI_FC_AUDICONF3 0x1028 +#define HDMI_FC_VSDIEEEID0 0x1029 +#define HDMI_FC_VSDSIZE 0x102A +#define HDMI_FC_VSDIEEEID1 0x1030 +#define HDMI_FC_VSDIEEEID2 0x1031 +#define HDMI_FC_VSDPAYLOAD0 0x1032 +#define HDMI_FC_VSDPAYLOAD1 0x1033 +#define HDMI_FC_VSDPAYLOAD2 0x1034 +#define HDMI_FC_VSDPAYLOAD3 0x1035 +#define HDMI_FC_VSDPAYLOAD4 0x1036 +#define HDMI_FC_VSDPAYLOAD5 0x1037 +#define HDMI_FC_VSDPAYLOAD6 0x1038 +#define HDMI_FC_VSDPAYLOAD7 0x1039 +#define HDMI_FC_VSDPAYLOAD8 0x103A +#define HDMI_FC_VSDPAYLOAD9 0x103B +#define HDMI_FC_VSDPAYLOAD10 0x103C +#define HDMI_FC_VSDPAYLOAD11 0x103D +#define HDMI_FC_VSDPAYLOAD12 0x103E +#define HDMI_FC_VSDPAYLOAD13 0x103F +#define HDMI_FC_VSDPAYLOAD14 0x1040 +#define HDMI_FC_VSDPAYLOAD15 0x1041 +#define HDMI_FC_VSDPAYLOAD16 0x1042 +#define HDMI_FC_VSDPAYLOAD17 0x1043 +#define HDMI_FC_VSDPAYLOAD18 0x1044 +#define HDMI_FC_VSDPAYLOAD19 0x1045 +#define HDMI_FC_VSDPAYLOAD20 0x1046 +#define HDMI_FC_VSDPAYLOAD21 0x1047 +#define HDMI_FC_VSDPAYLOAD22 0x1048 +#define HDMI_FC_VSDPAYLOAD23 0x1049 +#define HDMI_FC_SPDVENDORNAME0 0x104A +#define HDMI_FC_SPDVENDORNAME1 0x104B +#define HDMI_FC_SPDVENDORNAME2 0x104C +#define HDMI_FC_SPDVENDORNAME3 0x104D +#define HDMI_FC_SPDVENDORNAME4 0x104E +#define HDMI_FC_SPDVENDORNAME5 0x104F +#define HDMI_FC_SPDVENDORNAME6 0x1050 +#define HDMI_FC_SPDVENDORNAME7 0x1051 +#define HDMI_FC_SDPPRODUCTNAME0 0x1052 +#define HDMI_FC_SDPPRODUCTNAME1 0x1053 +#define HDMI_FC_SDPPRODUCTNAME2 0x1054 +#define HDMI_FC_SDPPRODUCTNAME3 0x1055 +#define HDMI_FC_SDPPRODUCTNAME4 0x1056 +#define HDMI_FC_SDPPRODUCTNAME5 0x1057 +#define HDMI_FC_SDPPRODUCTNAME6 0x1058 +#define HDMI_FC_SDPPRODUCTNAME7 0x1059 +#define HDMI_FC_SDPPRODUCTNAME8 0x105A +#define HDMI_FC_SDPPRODUCTNAME9 0x105B +#define HDMI_FC_SDPPRODUCTNAME10 0x105C +#define HDMI_FC_SDPPRODUCTNAME11 0x105D +#define HDMI_FC_SDPPRODUCTNAME12 0x105E +#define HDMI_FC_SDPPRODUCTNAME13 0x105F +#define HDMI_FC_SDPPRODUCTNAME14 0x1060 +#define HDMI_FC_SPDPRODUCTNAME15 0x1061 +#define HDMI_FC_SPDDEVICEINF 0x1062 +#define HDMI_FC_AUDSCONF 0x1063 +#define HDMI_FC_AUDSSTAT 0x1064 +#define HDMI_FC_DATACH0FILL 0x1070 +#define HDMI_FC_DATACH1FILL 0x1071 +#define HDMI_FC_DATACH2FILL 0x1072 +#define HDMI_FC_CTRLQHIGH 0x1073 +#define HDMI_FC_CTRLQLOW 0x1074 +#define HDMI_FC_ACP0 0x1075 +#define HDMI_FC_ACP28 0x1076 +#define HDMI_FC_ACP27 0x1077 +#define HDMI_FC_ACP26 0x1078 +#define HDMI_FC_ACP25 0x1079 +#define HDMI_FC_ACP24 0x107A +#define HDMI_FC_ACP23 0x107B +#define HDMI_FC_ACP22 0x107C +#define HDMI_FC_ACP21 0x107D +#define HDMI_FC_ACP20 0x107E +#define HDMI_FC_ACP19 0x107F +#define HDMI_FC_ACP18 0x1080 +#define HDMI_FC_ACP17 0x1081 +#define HDMI_FC_ACP16 0x1082 +#define HDMI_FC_ACP15 0x1083 +#define HDMI_FC_ACP14 0x1084 +#define HDMI_FC_ACP13 0x1085 +#define HDMI_FC_ACP12 0x1086 +#define HDMI_FC_ACP11 0x1087 +#define HDMI_FC_ACP10 0x1088 +#define HDMI_FC_ACP9 0x1089 +#define HDMI_FC_ACP8 0x108A +#define HDMI_FC_ACP7 0x108B +#define HDMI_FC_ACP6 0x108C +#define HDMI_FC_ACP5 0x108D +#define HDMI_FC_ACP4 0x108E +#define HDMI_FC_ACP3 0x108F +#define HDMI_FC_ACP2 0x1090 +#define HDMI_FC_ACP1 0x1091 +#define HDMI_FC_ISCR1_0 0x1092 +#define HDMI_FC_ISCR1_16 0x1093 +#define HDMI_FC_ISCR1_15 0x1094 +#define HDMI_FC_ISCR1_14 0x1095 +#define HDMI_FC_ISCR1_13 0x1096 +#define HDMI_FC_ISCR1_12 0x1097 +#define HDMI_FC_ISCR1_11 0x1098 +#define HDMI_FC_ISCR1_10 0x1099 +#define HDMI_FC_ISCR1_9 0x109A +#define HDMI_FC_ISCR1_8 0x109B +#define HDMI_FC_ISCR1_7 0x109C +#define HDMI_FC_ISCR1_6 0x109D +#define HDMI_FC_ISCR1_5 0x109E +#define HDMI_FC_ISCR1_4 0x109F +#define HDMI_FC_ISCR1_3 0x10A0 +#define HDMI_FC_ISCR1_2 0x10A1 +#define HDMI_FC_ISCR1_1 0x10A2 +#define HDMI_FC_ISCR2_15 0x10A3 +#define HDMI_FC_ISCR2_14 0x10A4 +#define HDMI_FC_ISCR2_13 0x10A5 +#define HDMI_FC_ISCR2_12 0x10A6 +#define HDMI_FC_ISCR2_11 0x10A7 +#define HDMI_FC_ISCR2_10 0x10A8 +#define HDMI_FC_ISCR2_9 0x10A9 +#define HDMI_FC_ISCR2_8 0x10AA +#define HDMI_FC_ISCR2_7 0x10AB +#define HDMI_FC_ISCR2_6 0x10AC +#define HDMI_FC_ISCR2_5 0x10AD +#define HDMI_FC_ISCR2_4 0x10AE +#define HDMI_FC_ISCR2_3 0x10AF +#define HDMI_FC_ISCR2_2 0x10B0 +#define HDMI_FC_ISCR2_1 0x10B1 +#define HDMI_FC_ISCR2_0 0x10B2 +#define HDMI_FC_DATAUTO0 0x10B3 +#define HDMI_FC_DATAUTO1 0x10B4 +#define HDMI_FC_DATAUTO2 0x10B5 +#define HDMI_FC_DATMAN 0x10B6 +#define HDMI_FC_DATAUTO3 0x10B7 +#define HDMI_FC_RDRB0 0x10B8 +#define HDMI_FC_RDRB1 0x10B9 +#define HDMI_FC_RDRB2 0x10BA +#define HDMI_FC_RDRB3 0x10BB +#define HDMI_FC_RDRB4 0x10BC +#define HDMI_FC_RDRB5 0x10BD +#define HDMI_FC_RDRB6 0x10BE +#define HDMI_FC_RDRB7 0x10BF +#define HDMI_FC_STAT0 0x10D0 +#define HDMI_FC_INT0 0x10D1 +#define HDMI_FC_MASK0 0x10D2 +#define HDMI_FC_POL0 0x10D3 +#define HDMI_FC_STAT1 0x10D4 +#define HDMI_FC_INT1 0x10D5 +#define HDMI_FC_MASK1 0x10D6 +#define HDMI_FC_POL1 0x10D7 +#define HDMI_FC_STAT2 0x10D8 +#define HDMI_FC_INT2 0x10D9 +#define HDMI_FC_MASK2 0x10DA +#define HDMI_FC_POL2 0x10DB +#define HDMI_FC_PRCONF 0x10E0 + +#define HDMI_FC_GMD_STAT 0x1100 +#define HDMI_FC_GMD_EN 0x1101 +#define HDMI_FC_GMD_UP 0x1102 +#define HDMI_FC_GMD_CONF 0x1103 +#define HDMI_FC_GMD_HB 0x1104 +#define HDMI_FC_GMD_PB0 0x1105 +#define HDMI_FC_GMD_PB1 0x1106 +#define HDMI_FC_GMD_PB2 0x1107 +#define HDMI_FC_GMD_PB3 0x1108 +#define HDMI_FC_GMD_PB4 0x1109 +#define HDMI_FC_GMD_PB5 0x110A +#define HDMI_FC_GMD_PB6 0x110B +#define HDMI_FC_GMD_PB7 0x110C +#define HDMI_FC_GMD_PB8 0x110D +#define HDMI_FC_GMD_PB9 0x110E +#define HDMI_FC_GMD_PB10 0x110F +#define HDMI_FC_GMD_PB11 0x1110 +#define HDMI_FC_GMD_PB12 0x1111 +#define HDMI_FC_GMD_PB13 0x1112 +#define HDMI_FC_GMD_PB14 0x1113 +#define HDMI_FC_GMD_PB15 0x1114 +#define HDMI_FC_GMD_PB16 0x1115 +#define HDMI_FC_GMD_PB17 0x1116 +#define HDMI_FC_GMD_PB18 0x1117 +#define HDMI_FC_GMD_PB19 0x1118 +#define HDMI_FC_GMD_PB20 0x1119 +#define HDMI_FC_GMD_PB21 0x111A +#define HDMI_FC_GMD_PB22 0x111B +#define HDMI_FC_GMD_PB23 0x111C +#define HDMI_FC_GMD_PB24 0x111D +#define HDMI_FC_GMD_PB25 0x111E +#define HDMI_FC_GMD_PB26 0x111F +#define HDMI_FC_GMD_PB27 0x1120 + +#define HDMI_FC_DBGFORCE 0x1200 +#define HDMI_FC_DBGAUD0CH0 0x1201 +#define HDMI_FC_DBGAUD1CH0 0x1202 +#define HDMI_FC_DBGAUD2CH0 0x1203 +#define HDMI_FC_DBGAUD0CH1 0x1204 +#define HDMI_FC_DBGAUD1CH1 0x1205 +#define HDMI_FC_DBGAUD2CH1 0x1206 +#define HDMI_FC_DBGAUD0CH2 0x1207 +#define HDMI_FC_DBGAUD1CH2 0x1208 +#define HDMI_FC_DBGAUD2CH2 0x1209 +#define HDMI_FC_DBGAUD0CH3 0x120A +#define HDMI_FC_DBGAUD1CH3 0x120B +#define HDMI_FC_DBGAUD2CH3 0x120C +#define HDMI_FC_DBGAUD0CH4 0x120D +#define HDMI_FC_DBGAUD1CH4 0x120E +#define HDMI_FC_DBGAUD2CH4 0x120F +#define HDMI_FC_DBGAUD0CH5 0x1210 +#define HDMI_FC_DBGAUD1CH5 0x1211 +#define HDMI_FC_DBGAUD2CH5 0x1212 +#define HDMI_FC_DBGAUD0CH6 0x1213 +#define HDMI_FC_DBGAUD1CH6 0x1214 +#define HDMI_FC_DBGAUD2CH6 0x1215 +#define HDMI_FC_DBGAUD0CH7 0x1216 +#define HDMI_FC_DBGAUD1CH7 0x1217 +#define HDMI_FC_DBGAUD2CH7 0x1218 +#define HDMI_FC_DBGTMDS0 0x1219 +#define HDMI_FC_DBGTMDS1 0x121A +#define HDMI_FC_DBGTMDS2 0x121B + +/* HDMI Source PHY Registers */ +#define HDMI_PHY_CONF0 0x3000 +#define HDMI_PHY_TST0 0x3001 +#define HDMI_PHY_TST1 0x3002 +#define HDMI_PHY_TST2 0x3003 +#define HDMI_PHY_STAT0 0x3004 +#define HDMI_PHY_INT0 0x3005 +#define HDMI_PHY_MASK0 0x3006 +#define HDMI_PHY_POL0 0x3007 + +/* HDMI Master PHY Registers */ +#define HDMI_PHY_I2CM_SLAVE_ADDR 0x3020 +#define HDMI_PHY_I2CM_ADDRESS_ADDR 0x3021 +#define HDMI_PHY_I2CM_DATAO_1_ADDR 0x3022 +#define HDMI_PHY_I2CM_DATAO_0_ADDR 0x3023 +#define HDMI_PHY_I2CM_DATAI_1_ADDR 0x3024 +#define HDMI_PHY_I2CM_DATAI_0_ADDR 0x3025 +#define HDMI_PHY_I2CM_OPERATION_ADDR 0x3026 +#define HDMI_PHY_I2CM_INT_ADDR 0x3027 +#define HDMI_PHY_I2CM_CTLINT_ADDR 0x3028 +#define HDMI_PHY_I2CM_DIV_ADDR 0x3029 +#define HDMI_PHY_I2CM_SOFTRSTZ_ADDR 0x302a +#define HDMI_PHY_I2CM_SS_SCL_HCNT_1_ADDR 0x302b +#define HDMI_PHY_I2CM_SS_SCL_HCNT_0_ADDR 0x302c +#define HDMI_PHY_I2CM_SS_SCL_LCNT_1_ADDR 0x302d +#define HDMI_PHY_I2CM_SS_SCL_LCNT_0_ADDR 0x302e +#define HDMI_PHY_I2CM_FS_SCL_HCNT_1_ADDR 0x302f +#define HDMI_PHY_I2CM_FS_SCL_HCNT_0_ADDR 0x3030 +#define HDMI_PHY_I2CM_FS_SCL_LCNT_1_ADDR 0x3031 +#define HDMI_PHY_I2CM_FS_SCL_LCNT_0_ADDR 0x3032 + +/* Audio Sampler Registers */ +#define HDMI_AUD_CONF0 0x3100 +#define HDMI_AUD_CONF1 0x3101 +#define HDMI_AUD_INT 0x3102 +#define HDMI_AUD_CONF2 0x3103 +#define HDMI_AUD_N1 0x3200 +#define HDMI_AUD_N2 0x3201 +#define HDMI_AUD_N3 0x3202 +#define HDMI_AUD_CTS1 0x3203 +#define HDMI_AUD_CTS2 0x3204 +#define HDMI_AUD_CTS3 0x3205 +#define HDMI_AUD_INPUTCLKFS 0x3206 +#define HDMI_AUD_SPDIFINT 0x3302 +#define HDMI_AUD_CONF0_HBR 0x3400 +#define HDMI_AUD_HBR_STATUS 0x3401 +#define HDMI_AUD_HBR_INT 0x3402 +#define HDMI_AUD_HBR_POL 0x3403 +#define HDMI_AUD_HBR_MASK 0x3404 + +/* + * Generic Parallel Audio Interface Registers + * Not used as GPAUD interface is not enabled in hw + */ +#define HDMI_GP_CONF0 0x3500 +#define HDMI_GP_CONF1 0x3501 +#define HDMI_GP_CONF2 0x3502 +#define HDMI_GP_STAT 0x3503 +#define HDMI_GP_INT 0x3504 +#define HDMI_GP_MASK 0x3505 +#define HDMI_GP_POL 0x3506 + +/* Audio DMA Registers */ +#define HDMI_AHB_DMA_CONF0 0x3600 +#define HDMI_AHB_DMA_START 0x3601 +#define HDMI_AHB_DMA_STOP 0x3602 +#define HDMI_AHB_DMA_THRSLD 0x3603 +#define HDMI_AHB_DMA_STRADDR0 0x3604 +#define HDMI_AHB_DMA_STRADDR1 0x3605 +#define HDMI_AHB_DMA_STRADDR2 0x3606 +#define HDMI_AHB_DMA_STRADDR3 0x3607 +#define HDMI_AHB_DMA_STPADDR0 0x3608 +#define HDMI_AHB_DMA_STPADDR1 0x3609 +#define HDMI_AHB_DMA_STPADDR2 0x360a +#define HDMI_AHB_DMA_STPADDR3 0x360b +#define HDMI_AHB_DMA_BSTADDR0 0x360c +#define HDMI_AHB_DMA_BSTADDR1 0x360d +#define HDMI_AHB_DMA_BSTADDR2 0x360e +#define HDMI_AHB_DMA_BSTADDR3 0x360f +#define HDMI_AHB_DMA_MBLENGTH0 0x3610 +#define HDMI_AHB_DMA_MBLENGTH1 0x3611 +#define HDMI_AHB_DMA_STAT 0x3612 +#define HDMI_AHB_DMA_INT 0x3613 +#define HDMI_AHB_DMA_MASK 0x3614 +#define HDMI_AHB_DMA_POL 0x3615 +#define HDMI_AHB_DMA_CONF1 0x3616 +#define HDMI_AHB_DMA_BUFFSTAT 0x3617 +#define HDMI_AHB_DMA_BUFFINT 0x3618 +#define HDMI_AHB_DMA_BUFFMASK 0x3619 +#define HDMI_AHB_DMA_BUFFPOL 0x361a + +/* Main Controller Registers */ +#define HDMI_MC_SFRDIV 0x4000 +#define HDMI_MC_CLKDIS 0x4001 +#define HDMI_MC_SWRSTZ 0x4002 +#define HDMI_MC_OPCTRL 0x4003 +#define HDMI_MC_FLOWCTRL 0x4004 +#define HDMI_MC_PHYRSTZ 0x4005 +#define HDMI_MC_LOCKONCLOCK 0x4006 +#define HDMI_MC_HEACPHY_RST 0x4007 + +/* Color Space Converter Registers */ +#define HDMI_CSC_CFG 0x4100 +#define HDMI_CSC_SCALE 0x4101 +#define HDMI_CSC_COEF_A1_MSB 0x4102 +#define HDMI_CSC_COEF_A1_LSB 0x4103 +#define HDMI_CSC_COEF_A2_MSB 0x4104 +#define HDMI_CSC_COEF_A2_LSB 0x4105 +#define HDMI_CSC_COEF_A3_MSB 0x4106 +#define HDMI_CSC_COEF_A3_LSB 0x4107 +#define HDMI_CSC_COEF_A4_MSB 0x4108 +#define HDMI_CSC_COEF_A4_LSB 0x4109 +#define HDMI_CSC_COEF_B1_MSB 0x410A +#define HDMI_CSC_COEF_B1_LSB 0x410B +#define HDMI_CSC_COEF_B2_MSB 0x410C +#define HDMI_CSC_COEF_B2_LSB 0x410D +#define HDMI_CSC_COEF_B3_MSB 0x410E +#define HDMI_CSC_COEF_B3_LSB 0x410F +#define HDMI_CSC_COEF_B4_MSB 0x4110 +#define HDMI_CSC_COEF_B4_LSB 0x4111 +#define HDMI_CSC_COEF_C1_MSB 0x4112 +#define HDMI_CSC_COEF_C1_LSB 0x4113 +#define HDMI_CSC_COEF_C2_MSB 0x4114 +#define HDMI_CSC_COEF_C2_LSB 0x4115 +#define HDMI_CSC_COEF_C3_MSB 0x4116 +#define HDMI_CSC_COEF_C3_LSB 0x4117 +#define HDMI_CSC_COEF_C4_MSB 0x4118 +#define HDMI_CSC_COEF_C4_LSB 0x4119 + +/* HDCP Encryption Engine Registers */ +#define HDMI_A_HDCPCFG0 0x5000 +#define HDMI_A_HDCPCFG1 0x5001 +#define HDMI_A_HDCPOBS0 0x5002 +#define HDMI_A_HDCPOBS1 0x5003 +#define HDMI_A_HDCPOBS2 0x5004 +#define HDMI_A_HDCPOBS3 0x5005 +#define HDMI_A_APIINTCLR 0x5006 +#define HDMI_A_APIINTSTAT 0x5007 +#define HDMI_A_APIINTMSK 0x5008 +#define HDMI_A_VIDPOLCFG 0x5009 +#define HDMI_A_OESSWCFG 0x500A +#define HDMI_A_TIMER1SETUP0 0x500B +#define HDMI_A_TIMER1SETUP1 0x500C +#define HDMI_A_TIMER2SETUP0 0x500D +#define HDMI_A_TIMER2SETUP1 0x500E +#define HDMI_A_100MSCFG 0x500F +#define HDMI_A_2SCFG0 0x5010 +#define HDMI_A_2SCFG1 0x5011 +#define HDMI_A_5SCFG0 0x5012 +#define HDMI_A_5SCFG1 0x5013 +#define HDMI_A_SRMVERLSB 0x5014 +#define HDMI_A_SRMVERMSB 0x5015 +#define HDMI_A_SRMCTRL 0x5016 +#define HDMI_A_SFRSETUP 0x5017 +#define HDMI_A_I2CHSETUP 0x5018 +#define HDMI_A_INTSETUP 0x5019 +#define HDMI_A_PRESETUP 0x501A +#define HDMI_A_SRM_BASE 0x5020 + +/* CEC Engine Registers */ +#define HDMI_CEC_CTRL 0x7D00 +#define HDMI_CEC_STAT 0x7D01 +#define HDMI_CEC_MASK 0x7D02 +#define HDMI_CEC_POLARITY 0x7D03 +#define HDMI_CEC_INT 0x7D04 +#define HDMI_CEC_ADDR_L 0x7D05 +#define HDMI_CEC_ADDR_H 0x7D06 +#define HDMI_CEC_TX_CNT 0x7D07 +#define HDMI_CEC_RX_CNT 0x7D08 +#define HDMI_CEC_TX_DATA0 0x7D10 +#define HDMI_CEC_TX_DATA1 0x7D11 +#define HDMI_CEC_TX_DATA2 0x7D12 +#define HDMI_CEC_TX_DATA3 0x7D13 +#define HDMI_CEC_TX_DATA4 0x7D14 +#define HDMI_CEC_TX_DATA5 0x7D15 +#define HDMI_CEC_TX_DATA6 0x7D16 +#define HDMI_CEC_TX_DATA7 0x7D17 +#define HDMI_CEC_TX_DATA8 0x7D18 +#define HDMI_CEC_TX_DATA9 0x7D19 +#define HDMI_CEC_TX_DATA10 0x7D1a +#define HDMI_CEC_TX_DATA11 0x7D1b +#define HDMI_CEC_TX_DATA12 0x7D1c +#define HDMI_CEC_TX_DATA13 0x7D1d +#define HDMI_CEC_TX_DATA14 0x7D1e +#define HDMI_CEC_TX_DATA15 0x7D1f +#define HDMI_CEC_RX_DATA0 0x7D20 +#define HDMI_CEC_RX_DATA1 0x7D21 +#define HDMI_CEC_RX_DATA2 0x7D22 +#define HDMI_CEC_RX_DATA3 0x7D23 +#define HDMI_CEC_RX_DATA4 0x7D24 +#define HDMI_CEC_RX_DATA5 0x7D25 +#define HDMI_CEC_RX_DATA6 0x7D26 +#define HDMI_CEC_RX_DATA7 0x7D27 +#define HDMI_CEC_RX_DATA8 0x7D28 +#define HDMI_CEC_RX_DATA9 0x7D29 +#define HDMI_CEC_RX_DATA10 0x7D2a +#define HDMI_CEC_RX_DATA11 0x7D2b +#define HDMI_CEC_RX_DATA12 0x7D2c +#define HDMI_CEC_RX_DATA13 0x7D2d +#define HDMI_CEC_RX_DATA14 0x7D2e +#define HDMI_CEC_RX_DATA15 0x7D2f +#define HDMI_CEC_LOCK 0x7D30 +#define HDMI_CEC_WKUPCTRL 0x7D31 + +/* I2C Master Registers (E-DDC) */ +#define HDMI_I2CM_SLAVE 0x7E00 +#define HDMI_I2CMESS 0x7E01 +#define HDMI_I2CM_DATAO 0x7E02 +#define HDMI_I2CM_DATAI 0x7E03 +#define HDMI_I2CM_OPERATION 0x7E04 +#define HDMI_I2CM_INT 0x7E05 +#define HDMI_I2CM_CTLINT 0x7E06 +#define HDMI_I2CM_DIV 0x7E07 +#define HDMI_I2CM_SEGADDR 0x7E08 +#define HDMI_I2CM_SOFTRSTZ 0x7E09 +#define HDMI_I2CM_SEGPTR 0x7E0A +#define HDMI_I2CM_SS_SCL_HCNT_1_ADDR 0x7E0B +#define HDMI_I2CM_SS_SCL_HCNT_0_ADDR 0x7E0C +#define HDMI_I2CM_SS_SCL_LCNT_1_ADDR 0x7E0D +#define HDMI_I2CM_SS_SCL_LCNT_0_ADDR 0x7E0E +#define HDMI_I2CM_FS_SCL_HCNT_1_ADDR 0x7E0F +#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR 0x7E10 +#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR 0x7E11 +#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12 + +enum { +/* IH_FC_INT2 field values */ + HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03, + HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02, + HDMI_IH_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01, + +/* IH_FC_STAT2 field values */ + HDMI_IH_FC_STAT2_OVERFLOW_MASK = 0x03, + HDMI_IH_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02, + HDMI_IH_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01, + +/* IH_PHY_STAT0 field values */ + HDMI_IH_PHY_STAT0_RX_SENSE3 = 0x20, + HDMI_IH_PHY_STAT0_RX_SENSE2 = 0x10, + HDMI_IH_PHY_STAT0_RX_SENSE1 = 0x8, + HDMI_IH_PHY_STAT0_RX_SENSE0 = 0x4, + HDMI_IH_PHY_STAT0_TX_PHY_LOCK = 0x2, + HDMI_IH_PHY_STAT0_HPD = 0x1, + +/* IH_MUTE_I2CMPHY_STAT0 field values */ + HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYDONE = 0x2, + HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYERROR = 0x1, + +/* IH_AHBDMAAUD_STAT0 field values */ + HDMI_IH_AHBDMAAUD_STAT0_ERROR = 0x20, + HDMI_IH_AHBDMAAUD_STAT0_LOST = 0x10, + HDMI_IH_AHBDMAAUD_STAT0_RETRY = 0x08, + HDMI_IH_AHBDMAAUD_STAT0_DONE = 0x04, + HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = 0x02, + HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01, + +/* IH_MUTE_FC_STAT2 field values */ + HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK = 0x03, + HDMI_IH_MUTE_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02, + HDMI_IH_MUTE_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01, + +/* IH_MUTE_AHBDMAAUD_STAT0 field values */ + HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = 0x20, + HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = 0x10, + HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = 0x08, + HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = 0x04, + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = 0x02, + HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01, + +/* IH_MUTE field values */ + HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT = 0x2, + HDMI_IH_MUTE_MUTE_ALL_INTERRUPT = 0x1, + +/* TX_INVID0 field values */ + HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_MASK = 0x80, + HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_ENABLE = 0x80, + HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE = 0x00, + HDMI_TX_INVID0_VIDEO_MAPPING_MASK = 0x1F, + HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET = 0, + +/* TX_INSTUFFING field values */ + HDMI_TX_INSTUFFING_BDBDATA_STUFFING_MASK = 0x4, + HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE = 0x4, + HDMI_TX_INSTUFFING_BDBDATA_STUFFING_DISABLE = 0x0, + HDMI_TX_INSTUFFING_RCRDATA_STUFFING_MASK = 0x2, + HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE = 0x2, + HDMI_TX_INSTUFFING_RCRDATA_STUFFING_DISABLE = 0x0, + HDMI_TX_INSTUFFING_GYDATA_STUFFING_MASK = 0x1, + HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE = 0x1, + HDMI_TX_INSTUFFING_GYDATA_STUFFING_DISABLE = 0x0, + +/* VP_PR_CD field values */ + HDMI_VP_PR_CD_COLOR_DEPTH_MASK = 0xF0, + HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET = 4, + HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK = 0x0F, + HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET = 0, + +/* VP_STUFF field values */ + HDMI_VP_STUFF_IDEFAULT_PHASE_MASK = 0x20, + HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET = 5, + HDMI_VP_STUFF_IFIX_PP_TO_LAST_MASK = 0x10, + HDMI_VP_STUFF_IFIX_PP_TO_LAST_OFFSET = 4, + HDMI_VP_STUFF_ICX_GOTO_P0_ST_MASK = 0x8, + HDMI_VP_STUFF_ICX_GOTO_P0_ST_OFFSET = 3, + HDMI_VP_STUFF_YCC422_STUFFING_MASK = 0x4, + HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE = 0x4, + HDMI_VP_STUFF_YCC422_STUFFING_DIRECT_MODE = 0x0, + HDMI_VP_STUFF_PP_STUFFING_MASK = 0x2, + HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE = 0x2, + HDMI_VP_STUFF_PP_STUFFING_DIRECT_MODE = 0x0, + HDMI_VP_STUFF_PR_STUFFING_MASK = 0x1, + HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE = 0x1, + HDMI_VP_STUFF_PR_STUFFING_DIRECT_MODE = 0x0, + +/* VP_CONF field values */ + HDMI_VP_CONF_BYPASS_EN_MASK = 0x40, + HDMI_VP_CONF_BYPASS_EN_ENABLE = 0x40, + HDMI_VP_CONF_BYPASS_EN_DISABLE = 0x00, + HDMI_VP_CONF_PP_EN_ENMASK = 0x20, + HDMI_VP_CONF_PP_EN_ENABLE = 0x20, + HDMI_VP_CONF_PP_EN_DISABLE = 0x00, + HDMI_VP_CONF_PR_EN_MASK = 0x10, + HDMI_VP_CONF_PR_EN_ENABLE = 0x10, + HDMI_VP_CONF_PR_EN_DISABLE = 0x00, + HDMI_VP_CONF_YCC422_EN_MASK = 0x8, + HDMI_VP_CONF_YCC422_EN_ENABLE = 0x8, + HDMI_VP_CONF_YCC422_EN_DISABLE = 0x0, + HDMI_VP_CONF_BYPASS_SELECT_MASK = 0x4, + HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER = 0x4, + HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER = 0x0, + HDMI_VP_CONF_OUTPUT_SELECTOR_MASK = 0x3, + HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS = 0x3, + HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422 = 0x1, + HDMI_VP_CONF_OUTPUT_SELECTOR_PP = 0x0, + +/* VP_REMAP field values */ + HDMI_VP_REMAP_MASK = 0x3, + HDMI_VP_REMAP_YCC422_24bit = 0x2, + HDMI_VP_REMAP_YCC422_20bit = 0x1, + HDMI_VP_REMAP_YCC422_16bit = 0x0, + +/* FC_INVIDCONF field values */ + HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK = 0x80, + HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE = 0x80, + HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE = 0x00, + HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_MASK = 0x40, + HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH = 0x40, + HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW = 0x00, + HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_MASK = 0x20, + HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH = 0x20, + HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW = 0x00, + HDMI_FC_INVIDCONF_DE_IN_POLARITY_MASK = 0x10, + HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH = 0x10, + HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW = 0x00, + HDMI_FC_INVIDCONF_DVI_MODEZ_MASK = 0x8, + HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE = 0x8, + HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE = 0x0, + HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_MASK = 0x2, + HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH = 0x2, + HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW = 0x0, + HDMI_FC_INVIDCONF_IN_I_P_MASK = 0x1, + HDMI_FC_INVIDCONF_IN_I_P_INTERLACED = 0x1, + HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE = 0x0, + +/* FC_AUDICONF0 field values */ + HDMI_FC_AUDICONF0_CC_OFFSET = 4, + HDMI_FC_AUDICONF0_CC_MASK = 0x70, + HDMI_FC_AUDICONF0_CT_OFFSET = 0, + HDMI_FC_AUDICONF0_CT_MASK = 0xF, + +/* FC_AUDICONF1 field values */ + HDMI_FC_AUDICONF1_SS_OFFSET = 3, + HDMI_FC_AUDICONF1_SS_MASK = 0x18, + HDMI_FC_AUDICONF1_SF_OFFSET = 0, + HDMI_FC_AUDICONF1_SF_MASK = 0x7, + +/* FC_AUDICONF3 field values */ + HDMI_FC_AUDICONF3_LFEPBL_OFFSET = 5, + HDMI_FC_AUDICONF3_LFEPBL_MASK = 0x60, + HDMI_FC_AUDICONF3_DM_INH_OFFSET = 4, + HDMI_FC_AUDICONF3_DM_INH_MASK = 0x10, + HDMI_FC_AUDICONF3_LSV_OFFSET = 0, + HDMI_FC_AUDICONF3_LSV_MASK = 0xF, + +/* FC_AUDSCHNLS0 field values */ + HDMI_FC_AUDSCHNLS0_CGMSA_OFFSET = 4, + HDMI_FC_AUDSCHNLS0_CGMSA_MASK = 0x30, + HDMI_FC_AUDSCHNLS0_COPYRIGHT_OFFSET = 0, + HDMI_FC_AUDSCHNLS0_COPYRIGHT_MASK = 0x01, + +/* FC_AUDSCHNLS3-6 field values */ + HDMI_FC_AUDSCHNLS3_OIEC_CH0_OFFSET = 0, + HDMI_FC_AUDSCHNLS3_OIEC_CH0_MASK = 0x0f, + HDMI_FC_AUDSCHNLS3_OIEC_CH1_OFFSET = 4, + HDMI_FC_AUDSCHNLS3_OIEC_CH1_MASK = 0xf0, + HDMI_FC_AUDSCHNLS4_OIEC_CH2_OFFSET = 0, + HDMI_FC_AUDSCHNLS4_OIEC_CH2_MASK = 0x0f, + HDMI_FC_AUDSCHNLS4_OIEC_CH3_OFFSET = 4, + HDMI_FC_AUDSCHNLS4_OIEC_CH3_MASK = 0xf0, + + HDMI_FC_AUDSCHNLS5_OIEC_CH0_OFFSET = 0, + HDMI_FC_AUDSCHNLS5_OIEC_CH0_MASK = 0x0f, + HDMI_FC_AUDSCHNLS5_OIEC_CH1_OFFSET = 4, + HDMI_FC_AUDSCHNLS5_OIEC_CH1_MASK = 0xf0, + HDMI_FC_AUDSCHNLS6_OIEC_CH2_OFFSET = 0, + HDMI_FC_AUDSCHNLS6_OIEC_CH2_MASK = 0x0f, + HDMI_FC_AUDSCHNLS6_OIEC_CH3_OFFSET = 4, + HDMI_FC_AUDSCHNLS6_OIEC_CH3_MASK = 0xf0, + +/* HDMI_FC_AUDSCHNLS7 field values */ + HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4, + HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30, + +/* HDMI_FC_AUDSCHNLS8 field values */ + HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0, + HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET = 4, + HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f, + HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0, + +/* FC_AUDSCONF field values */ + HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0, + HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4, + HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK = 0x1, + HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_OFFSET = 0, + HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1 = 0x1, + HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0 = 0x0, + +/* FC_STAT2 field values */ + HDMI_FC_STAT2_OVERFLOW_MASK = 0x03, + HDMI_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02, + HDMI_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01, + +/* FC_INT2 field values */ + HDMI_FC_INT2_OVERFLOW_MASK = 0x03, + HDMI_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02, + HDMI_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01, + +/* FC_MASK2 field values */ + HDMI_FC_MASK2_OVERFLOW_MASK = 0x03, + HDMI_FC_MASK2_LOW_PRIORITY_OVERFLOW = 0x02, + HDMI_FC_MASK2_HIGH_PRIORITY_OVERFLOW = 0x01, + +/* FC_PRCONF field values */ + HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK = 0xF0, + HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET = 4, + HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F, + HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0, + +/* FC_AVICONF0-FC_AVICONF3 field values */ + HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03, + HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00, + HDMI_FC_AVICONF0_PIX_FMT_YCBCR422 = 0x01, + HDMI_FC_AVICONF0_PIX_FMT_YCBCR444 = 0x02, + HDMI_FC_AVICONF0_ACTIVE_FMT_MASK = 0x40, + HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT = 0x40, + HDMI_FC_AVICONF0_ACTIVE_FMT_NO_INFO = 0x00, + HDMI_FC_AVICONF0_BAR_DATA_MASK = 0x0C, + HDMI_FC_AVICONF0_BAR_DATA_NO_DATA = 0x00, + HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR = 0x04, + HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR = 0x08, + HDMI_FC_AVICONF0_BAR_DATA_VERT_HORIZ_BAR = 0x0C, + HDMI_FC_AVICONF0_SCAN_INFO_MASK = 0x30, + HDMI_FC_AVICONF0_SCAN_INFO_OVERSCAN = 0x10, + HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN = 0x20, + HDMI_FC_AVICONF0_SCAN_INFO_NODATA = 0x00, + + HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_MASK = 0x0F, + HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_USE_CODED = 0x08, + HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3 = 0x09, + HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9 = 0x0A, + HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_14_9 = 0x0B, + HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_MASK = 0x30, + HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_NO_DATA = 0x00, + HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3 = 0x10, + HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9 = 0x20, + HDMI_FC_AVICONF1_COLORIMETRY_MASK = 0xC0, + HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA = 0x00, + HDMI_FC_AVICONF1_COLORIMETRY_SMPTE = 0x40, + HDMI_FC_AVICONF1_COLORIMETRY_ITUR = 0x80, + HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO = 0xC0, + + HDMI_FC_AVICONF2_SCALING_MASK = 0x03, + HDMI_FC_AVICONF2_SCALING_NONE = 0x00, + HDMI_FC_AVICONF2_SCALING_HORIZ = 0x01, + HDMI_FC_AVICONF2_SCALING_VERT = 0x02, + HDMI_FC_AVICONF2_SCALING_HORIZ_VERT = 0x03, + HDMI_FC_AVICONF2_RGB_QUANT_MASK = 0x0C, + HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT = 0x00, + HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE = 0x04, + HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE = 0x08, + HDMI_FC_AVICONF2_EXT_COLORIMETRY_MASK = 0x70, + HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601 = 0x00, + HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709 = 0x10, + HDMI_FC_AVICONF2_EXT_COLORIMETRY_SYCC601 = 0x20, + HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_YCC601 = 0x30, + HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_RGB = 0x40, + HDMI_FC_AVICONF2_IT_CONTENT_MASK = 0x80, + HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA = 0x00, + HDMI_FC_AVICONF2_IT_CONTENT_VALID = 0x80, + + HDMI_FC_AVICONF3_IT_CONTENT_TYPE_MASK = 0x03, + HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS = 0x00, + HDMI_FC_AVICONF3_IT_CONTENT_TYPE_PHOTO = 0x01, + HDMI_FC_AVICONF3_IT_CONTENT_TYPE_CINEMA = 0x02, + HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GAME = 0x03, + HDMI_FC_AVICONF3_QUANT_RANGE_MASK = 0x0C, + HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00, + HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04, + +/* FC_DBGFORCE field values */ + HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10, + HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1, + +/* PHY_CONF0 field values */ + HDMI_PHY_CONF0_PDZ_MASK = 0x80, + HDMI_PHY_CONF0_PDZ_OFFSET = 7, + HDMI_PHY_CONF0_ENTMDS_MASK = 0x40, + HDMI_PHY_CONF0_ENTMDS_OFFSET = 6, + HDMI_PHY_CONF0_SPARECTRL = 0x20, + HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10, + HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4, + HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8, + HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET = 3, + HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_MASK = 0x4, + HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_OFFSET = 2, + HDMI_PHY_CONF0_SELDATAENPOL_MASK = 0x2, + HDMI_PHY_CONF0_SELDATAENPOL_OFFSET = 1, + HDMI_PHY_CONF0_SELDIPIF_MASK = 0x1, + HDMI_PHY_CONF0_SELDIPIF_OFFSET = 0, + +/* PHY_TST0 field values */ + HDMI_PHY_TST0_TSTCLR_MASK = 0x20, + HDMI_PHY_TST0_TSTCLR_OFFSET = 5, + HDMI_PHY_TST0_TSTEN_MASK = 0x10, + HDMI_PHY_TST0_TSTEN_OFFSET = 4, + HDMI_PHY_TST0_TSTCLK_MASK = 0x1, + HDMI_PHY_TST0_TSTCLK_OFFSET = 0, + +/* PHY_STAT0 field values */ + HDMI_PHY_RX_SENSE3 = 0x80, + HDMI_PHY_RX_SENSE2 = 0x40, + HDMI_PHY_RX_SENSE1 = 0x20, + HDMI_PHY_RX_SENSE0 = 0x10, + HDMI_PHY_HPD = 0x02, + HDMI_PHY_TX_PHY_LOCK = 0x01, + +/* PHY_I2CM_SLAVE_ADDR field values */ + HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 = 0x69, + HDMI_PHY_I2CM_SLAVE_ADDR_HEAC_PHY = 0x49, + +/* PHY_I2CM_OPERATION_ADDR field values */ + HDMI_PHY_I2CM_OPERATION_ADDR_WRITE = 0x10, + HDMI_PHY_I2CM_OPERATION_ADDR_READ = 0x1, + +/* HDMI_PHY_I2CM_INT_ADDR */ + HDMI_PHY_I2CM_INT_ADDR_DONE_POL = 0x08, + HDMI_PHY_I2CM_INT_ADDR_DONE_MASK = 0x04, + +/* HDMI_PHY_I2CM_CTLINT_ADDR */ + HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL = 0x80, + HDMI_PHY_I2CM_CTLINT_ADDR_NAC_MASK = 0x40, + HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08, + HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04, + +/* AUD_CTS3 field values */ + HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5, + HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0, + HDMI_AUD_CTS3_N_SHIFT_1 = 0, + HDMI_AUD_CTS3_N_SHIFT_16 = 0x20, + HDMI_AUD_CTS3_N_SHIFT_32 = 0x40, + HDMI_AUD_CTS3_N_SHIFT_64 = 0x60, + HDMI_AUD_CTS3_N_SHIFT_128 = 0x80, + HDMI_AUD_CTS3_N_SHIFT_256 = 0xa0, + /* note that the CTS3 MANUAL bit has been removed + from our part. Can't set it, will read as 0. */ + HDMI_AUD_CTS3_CTS_MANUAL = 0x10, + HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f, + +/* AHB_DMA_CONF0 field values */ + HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7, + HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80, + HDMI_AHB_DMA_CONF0_HBR = 0x10, + HDMI_AHB_DMA_CONF0_EN_HLOCK_OFFSET = 3, + HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK = 0x08, + HDMI_AHB_DMA_CONF0_INCR_TYPE_OFFSET = 1, + HDMI_AHB_DMA_CONF0_INCR_TYPE_MASK = 0x06, + HDMI_AHB_DMA_CONF0_INCR4 = 0x0, + HDMI_AHB_DMA_CONF0_INCR8 = 0x2, + HDMI_AHB_DMA_CONF0_INCR16 = 0x4, + HDMI_AHB_DMA_CONF0_BURST_MODE = 0x1, + +/* HDMI_AHB_DMA_START field values */ + HDMI_AHB_DMA_START_START_OFFSET = 0, + HDMI_AHB_DMA_START_START_MASK = 0x01, + +/* HDMI_AHB_DMA_STOP field values */ + HDMI_AHB_DMA_STOP_STOP_OFFSET = 0, + HDMI_AHB_DMA_STOP_STOP_MASK = 0x01, + +/* AHB_DMA_STAT, AHB_DMA_INT, AHB_DMA_MASK, AHB_DMA_POL field values */ + HDMI_AHB_DMA_DONE = 0x80, + HDMI_AHB_DMA_RETRY_SPLIT = 0x40, + HDMI_AHB_DMA_LOSTOWNERSHIP = 0x20, + HDMI_AHB_DMA_ERROR = 0x10, + HDMI_AHB_DMA_FIFO_THREMPTY = 0x04, + HDMI_AHB_DMA_FIFO_FULL = 0x02, + HDMI_AHB_DMA_FIFO_EMPTY = 0x01, + +/* AHB_DMA_BUFFSTAT, AHB_DMA_BUFFINT,AHB_DMA_BUFFMASK,AHB_DMA_BUFFPOL values */ + HDMI_AHB_DMA_BUFFSTAT_FULL = 0x02, + HDMI_AHB_DMA_BUFFSTAT_EMPTY = 0x01, + +/* MC_CLKDIS field values */ + HDMI_MC_CLKDIS_HDCPCLK_DISABLE = 0x40, + HDMI_MC_CLKDIS_CECCLK_DISABLE = 0x20, + HDMI_MC_CLKDIS_CSCCLK_DISABLE = 0x10, + HDMI_MC_CLKDIS_AUDCLK_DISABLE = 0x8, + HDMI_MC_CLKDIS_PREPCLK_DISABLE = 0x4, + HDMI_MC_CLKDIS_TMDSCLK_DISABLE = 0x2, + HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1, + +/* MC_SWRSTZ field values */ + HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02, + +/* MC_FLOWCTRL field values */ + HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_MASK = 0x1, + HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH = 0x1, + HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0, + +/* MC_PHYRSTZ field values */ + HDMI_MC_PHYRSTZ_ASSERT = 0x0, + HDMI_MC_PHYRSTZ_DEASSERT = 0x1, + +/* MC_HEACPHY_RST field values */ + HDMI_MC_HEACPHY_RST_ASSERT = 0x1, + HDMI_MC_HEACPHY_RST_DEASSERT = 0x0, + +/* CSC_CFG field values */ + HDMI_CSC_CFG_INTMODE_MASK = 0x30, + HDMI_CSC_CFG_INTMODE_OFFSET = 4, + HDMI_CSC_CFG_INTMODE_DISABLE = 0x00, + HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 = 0x10, + HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA2 = 0x20, + HDMI_CSC_CFG_DECMODE_MASK = 0x3, + HDMI_CSC_CFG_DECMODE_OFFSET = 0, + HDMI_CSC_CFG_DECMODE_DISABLE = 0x0, + HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1 = 0x1, + HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA2 = 0x2, + HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 = 0x3, + +/* CSC_SCALE field values */ + HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK = 0xF0, + HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP = 0x00, + HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP = 0x50, + HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP = 0x60, + HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP = 0x70, + HDMI_CSC_SCALE_CSCSCALE_MASK = 0x03, + +/* A_HDCPCFG0 field values */ + HDMI_A_HDCPCFG0_ELVENA_MASK = 0x80, + HDMI_A_HDCPCFG0_ELVENA_ENABLE = 0x80, + HDMI_A_HDCPCFG0_ELVENA_DISABLE = 0x00, + HDMI_A_HDCPCFG0_I2CFASTMODE_MASK = 0x40, + HDMI_A_HDCPCFG0_I2CFASTMODE_ENABLE = 0x40, + HDMI_A_HDCPCFG0_I2CFASTMODE_DISABLE = 0x00, + HDMI_A_HDCPCFG0_BYPENCRYPTION_MASK = 0x20, + HDMI_A_HDCPCFG0_BYPENCRYPTION_ENABLE = 0x20, + HDMI_A_HDCPCFG0_BYPENCRYPTION_DISABLE = 0x00, + HDMI_A_HDCPCFG0_SYNCRICHECK_MASK = 0x10, + HDMI_A_HDCPCFG0_SYNCRICHECK_ENABLE = 0x10, + HDMI_A_HDCPCFG0_SYNCRICHECK_DISABLE = 0x00, + HDMI_A_HDCPCFG0_AVMUTE_MASK = 0x8, + HDMI_A_HDCPCFG0_AVMUTE_ENABLE = 0x8, + HDMI_A_HDCPCFG0_AVMUTE_DISABLE = 0x0, + HDMI_A_HDCPCFG0_RXDETECT_MASK = 0x4, + HDMI_A_HDCPCFG0_RXDETECT_ENABLE = 0x4, + HDMI_A_HDCPCFG0_RXDETECT_DISABLE = 0x0, + HDMI_A_HDCPCFG0_EN11FEATURE_MASK = 0x2, + HDMI_A_HDCPCFG0_EN11FEATURE_ENABLE = 0x2, + HDMI_A_HDCPCFG0_EN11FEATURE_DISABLE = 0x0, + HDMI_A_HDCPCFG0_HDMIDVI_MASK = 0x1, + HDMI_A_HDCPCFG0_HDMIDVI_HDMI = 0x1, + HDMI_A_HDCPCFG0_HDMIDVI_DVI = 0x0, + +/* A_HDCPCFG1 field values */ + HDMI_A_HDCPCFG1_DISSHA1CHECK_MASK = 0x8, + HDMI_A_HDCPCFG1_DISSHA1CHECK_DISABLE = 0x8, + HDMI_A_HDCPCFG1_DISSHA1CHECK_ENABLE = 0x0, + HDMI_A_HDCPCFG1_PH2UPSHFTENC_MASK = 0x4, + HDMI_A_HDCPCFG1_PH2UPSHFTENC_ENABLE = 0x4, + HDMI_A_HDCPCFG1_PH2UPSHFTENC_DISABLE = 0x0, + HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK = 0x2, + HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE = 0x2, + HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_ENABLE = 0x0, + HDMI_A_HDCPCFG1_SWRESET_MASK = 0x1, + HDMI_A_HDCPCFG1_SWRESET_ASSERT = 0x0, + +/* A_VIDPOLCFG field values */ + HDMI_A_VIDPOLCFG_UNENCRYPTCONF_MASK = 0x60, + HDMI_A_VIDPOLCFG_UNENCRYPTCONF_OFFSET = 5, + HDMI_A_VIDPOLCFG_DATAENPOL_MASK = 0x10, + HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH = 0x10, + HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW = 0x0, + HDMI_A_VIDPOLCFG_VSYNCPOL_MASK = 0x8, + HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH = 0x8, + HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW = 0x0, + HDMI_A_VIDPOLCFG_HSYNCPOL_MASK = 0x2, + HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2, + HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0, +}; +#endif /* __IMX_HDMI_H__ */ diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h index b6d36b38b99c..866e355fa409 100644 --- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h +++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h @@ -212,6 +212,7 @@ #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU1_DI1 (0x1 << 4) #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU2_DI0 (0x2 << 4) #define IMX6Q_GPR3_MIPI_MUX_CTL_IPU2_DI1 (0x3 << 4) +#define IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT 2 #define IMX6Q_GPR3_HDMI_MUX_CTL_MASK (0x3 << 2) #define IMX6Q_GPR3_HDMI_MUX_CTL_IPU1_DI0 (0x0 << 2) #define IMX6Q_GPR3_HDMI_MUX_CTL_IPU1_DI1 (0x1 << 2) -- cgit v1.2.3-59-g8ed1b From 0d6077f8b48ed2dce8f2466a76c0d574a3b4dbe9 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Tue, 26 Nov 2013 12:43:37 +0800 Subject: lib/scatterlist: export sg_miter_skip() sg_copy_buffer() can't meet demand for some drrivers(such usb mass storage), so we have to use the sg_miter_* APIs to access sg buffer, then need export sg_miter_skip() for these drivers. The API is needed for converting to sg_miter_* APIs in USB storage driver for accessing sg buffer. Acked-by: Andrew Morton Cc: FUJITA Tomonori Cc: Jens Axboe Signed-off-by: Ming Lei Reviewed-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- include/linux/scatterlist.h | 1 + lib/scatterlist.c | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index adae88f5b0ab..a964f7285600 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h @@ -345,6 +345,7 @@ struct sg_mapping_iter { void sg_miter_start(struct sg_mapping_iter *miter, struct scatterlist *sgl, unsigned int nents, unsigned int flags); +bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset); bool sg_miter_next(struct sg_mapping_iter *miter); void sg_miter_stop(struct sg_mapping_iter *miter); diff --git a/lib/scatterlist.c b/lib/scatterlist.c index d16fa295ae1d..3a8e8e8fb2a5 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -495,7 +495,7 @@ static bool sg_miter_get_next_page(struct sg_mapping_iter *miter) * true if @miter contains the valid mapping. false if end of sg * list is reached. */ -static bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset) +bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset) { sg_miter_stop(miter); @@ -513,6 +513,7 @@ static bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset) return true; } +EXPORT_SYMBOL(sg_miter_skip); /** * sg_miter_next - proceed mapping iterator to the next mapping -- cgit v1.2.3-59-g8ed1b From 103e127d1f8f985e8a662da6537ebc5e08902ee3 Mon Sep 17 00:00:00 2001 From: Valentine Barshak Date: Wed, 4 Dec 2013 01:42:21 +0400 Subject: usb: hcd: Remove USB phy if needed This adds remove_phy flag to the HCD structure. If the flag is set and if hcd->phy is valid, the phy is shutdown and released whenever usb_add_hcd fails or usb_hcd_remove is called. This can be used by the HCD drivers to auto-remove the external USB phy when it is no longer needed. Signed-off-by: Valentine Barshak Acked-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/core/hcd.c | 14 +++++++++++++- include/linux/usb/hcd.h | 1 + 2 files changed, 14 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 6bffb8c87bc9..7527c8e4ec64 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -44,6 +44,7 @@ #include #include +#include #include "usb.h" @@ -2603,7 +2604,7 @@ int usb_add_hcd(struct usb_hcd *hcd, */ if ((retval = hcd_buffer_create(hcd)) != 0) { dev_dbg(hcd->self.controller, "pool alloc failed\n"); - return retval; + goto err_remove_phy; } if ((retval = usb_register_bus(&hcd->self)) < 0) @@ -2734,6 +2735,12 @@ err_allocate_root_hub: usb_deregister_bus(&hcd->self); err_register_bus: hcd_buffer_destroy(hcd); +err_remove_phy: + if (hcd->remove_phy && hcd->phy) { + usb_phy_shutdown(hcd->phy); + usb_put_phy(hcd->phy); + hcd->phy = NULL; + } return retval; } EXPORT_SYMBOL_GPL(usb_add_hcd); @@ -2806,6 +2813,11 @@ void usb_remove_hcd(struct usb_hcd *hcd) usb_put_dev(hcd->self.root_hub); usb_deregister_bus(&hcd->self); hcd_buffer_destroy(hcd); + if (hcd->remove_phy && hcd->phy) { + usb_phy_shutdown(hcd->phy); + usb_put_phy(hcd->phy); + hcd->phy = NULL; + } } EXPORT_SYMBOL_GPL(usb_remove_hcd); diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index b8aba196f7f1..758ce80d085f 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -134,6 +134,7 @@ struct usb_hcd { unsigned rh_registered:1;/* is root hub registered? */ unsigned rh_pollable:1; /* may we poll the root hub? */ unsigned msix_enabled:1; /* driver has MSI-X enabled? */ + unsigned remove_phy:1; /* auto-remove USB phy */ /* The next flag is a stopgap, to be removed when all the HCDs * support the new root-hub polling mechanism. */ -- cgit v1.2.3-59-g8ed1b From 0d4e5bee27dc2f3aa2b0a8a2e0313bfcaf4c5389 Mon Sep 17 00:00:00 2001 From: Yijing Wang Date: Thu, 5 Dec 2013 19:21:42 +0800 Subject: uwb: Use dev_is_pci() to check whether it is pci device Use PCI standard marco dev_is_pci() instead of directly compare pci_bus_type to check whether it is pci device. Signed-off-by: Yijing Wang Signed-off-by: Greg Kroah-Hartman --- drivers/uwb/umc-bus.c | 2 +- include/linux/uwb/umc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/uwb/umc-bus.c b/drivers/uwb/umc-bus.c index e3ed6ff6a481..88a290f57ea0 100644 --- a/drivers/uwb/umc-bus.c +++ b/drivers/uwb/umc-bus.c @@ -85,7 +85,7 @@ int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc) const struct pci_device_id *id_table = umc_drv->match_data; struct pci_dev *pci; - if (umc->dev.parent->bus != &pci_bus_type) + if (!dev_is_pci(umc->dev.parent)) return 0; pci = to_pci_dev(umc->dev.parent); diff --git a/include/linux/uwb/umc.h b/include/linux/uwb/umc.h index 891d1d5f3947..ba82f03d8287 100644 --- a/include/linux/uwb/umc.h +++ b/include/linux/uwb/umc.h @@ -143,7 +143,7 @@ int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc); static inline struct pci_dev *umc_parent_pci_dev(struct umc_dev *umc_dev) { struct pci_dev *pci_dev = NULL; - if (umc_dev->dev.parent->bus == &pci_bus_type) + if (dev_is_pci(umc_dev->dev.parent)) pci_dev = to_pci_dev(umc_dev->dev.parent); return pci_dev; } -- cgit v1.2.3-59-g8ed1b From bba3a87e982ad5992e776ca1fc409326915d6b44 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 2 Dec 2013 15:38:16 +0100 Subject: firmware: Introduce request_firmware_direct() When CONFIG_FW_LOADER_USER_HELPER is set, request_firmware() falls back to the usermode helper for loading via udev when the direct loading fails. But the recent udev takes way too long timeout (60 seconds) for non-existing firmware. This is unacceptable for the drivers like microcode loader where they load firmwares optionally, i.e. it's no error even if no requested file exists. This patch provides a new helper function, request_firmware_direct(). It behaves as same as request_firmware() except for that it doesn't fall back to usermode helper but returns an error immediately if the f/w can't be loaded directly in kernel. Without CONFIG_FW_LOADER_USER_HELPER=y, request_firmware_direct() is just an alias of request_firmware(), due to obvious reason. Tested-by: Prarit Bhargava Acked-by: Ming Lei Acked-by: Borislav Petkov Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- drivers/base/firmware_class.c | 41 ++++++++++++++++++++++++++++++++++------- include/linux/firmware.h | 7 +++++++ 2 files changed, 41 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index eb8fb94ae2c5..1af03648daf8 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -1061,7 +1061,7 @@ static int assign_firmware_buf(struct firmware *fw, struct device *device, /* called from request_firmware() and request_firmware_work_func() */ static int _request_firmware(const struct firmware **firmware_p, const char *name, - struct device *device, bool uevent, bool nowait) + struct device *device, bool uevent, bool nowait, bool fallback) { struct firmware *fw; long timeout; @@ -1095,11 +1095,14 @@ _request_firmware(const struct firmware **firmware_p, const char *name, ret = fw_get_filesystem_firmware(device, fw->priv); if (ret) { - dev_warn(device, "Direct firmware load failed with error %d\n", - ret); - dev_warn(device, "Falling back to user helper\n"); - ret = fw_load_from_user_helper(fw, name, device, + if (fallback) { + dev_warn(device, + "Direct firmware load failed with error %d\n", + ret); + dev_warn(device, "Falling back to user helper\n"); + ret = fw_load_from_user_helper(fw, name, device, uevent, nowait, timeout); + } } /* don't cache firmware handled without uevent */ @@ -1146,12 +1149,36 @@ request_firmware(const struct firmware **firmware_p, const char *name, /* Need to pin this module until return */ __module_get(THIS_MODULE); - ret = _request_firmware(firmware_p, name, device, true, false); + ret = _request_firmware(firmware_p, name, device, true, false, true); module_put(THIS_MODULE); return ret; } EXPORT_SYMBOL(request_firmware); +#ifdef CONFIG_FW_LOADER_USER_HELPER +/** + * request_firmware: - load firmware directly without usermode helper + * @firmware_p: pointer to firmware image + * @name: name of firmware file + * @device: device for which firmware is being loaded + * + * This function works pretty much like request_firmware(), but this doesn't + * fall back to usermode helper even if the firmware couldn't be loaded + * directly from fs. Hence it's useful for loading optional firmwares, which + * aren't always present, without extra long timeouts of udev. + **/ +int request_firmware_direct(const struct firmware **firmware_p, + const char *name, struct device *device) +{ + int ret; + __module_get(THIS_MODULE); + ret = _request_firmware(firmware_p, name, device, true, false, false); + module_put(THIS_MODULE); + return ret; +} +EXPORT_SYMBOL_GPL(request_firmware_direct); +#endif + /** * release_firmware: - release the resource associated with a firmware image * @fw: firmware resource to release @@ -1185,7 +1212,7 @@ static void request_firmware_work_func(struct work_struct *work) fw_work = container_of(work, struct firmware_work, work); _request_firmware(&fw, fw_work->name, fw_work->device, - fw_work->uevent, true); + fw_work->uevent, true, true); fw_work->cont(fw, fw_work->context); put_device(fw_work->device); /* taken in request_firmware_nowait() */ diff --git a/include/linux/firmware.h b/include/linux/firmware.h index e154c1005cd1..59529330efd6 100644 --- a/include/linux/firmware.h +++ b/include/linux/firmware.h @@ -68,4 +68,11 @@ static inline void release_firmware(const struct firmware *fw) #endif +#ifdef CONFIG_FW_LOADER_USER_HELPER +int request_firmware_direct(const struct firmware **fw, const char *name, + struct device *device); +#else +#define request_firmware_direct request_firmware +#endif + #endif -- cgit v1.2.3-59-g8ed1b From ad824783fb23bbc8295cffb6214b3b82d25f7d4a Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 3 Dec 2013 12:20:11 +0900 Subject: gpio: better lookup method for platform GPIOs Change the format of the platform GPIO lookup tables to make them less confusing and improve lookup efficiency. The previous format was a single linked-list that required to compare the device name and function ID of every single GPIO defined for each lookup. Switch that to a list of per-device tables, so that the lookup can be done in two steps, omitting the GPIOs that are not relevant for a particular device. The matching rules are now defined as follows: - The device name must match *exactly*, and can be NULL for GPIOs not assigned to a particular device, - If the function ID in the lookup table is NULL, the con_id argument of gpiod_get() will not be used for lookup. However, if it is defined, it must match exactly. - The index must always match. Signed-off-by: Alexandre Courbot Acked-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Linus Walleij --- Documentation/gpio/board.txt | 28 ++++++----- drivers/gpio/gpiolib.c | 108 +++++++++++++++++++++++-------------------- include/linux/gpio/driver.h | 21 ++++----- 3 files changed, 85 insertions(+), 72 deletions(-) (limited to 'include/linux') diff --git a/Documentation/gpio/board.txt b/Documentation/gpio/board.txt index 0d03506f2cc5..ba169faad5c6 100644 --- a/Documentation/gpio/board.txt +++ b/Documentation/gpio/board.txt @@ -72,10 +72,11 @@ where - chip_label is the label of the gpiod_chip instance providing the GPIO - chip_hwnum is the hardware number of the GPIO within the chip - - dev_id is the identifier of the device that will make use of this GPIO. If - NULL, the GPIO will be available to all devices. + - dev_id is the identifier of the device that will make use of this GPIO. It + can be NULL, in which case it will be matched for calls to gpiod_get() + with a NULL device. - con_id is the name of the GPIO function from the device point of view. It - can be NULL. + can be NULL, in which case it will match any function. - idx is the index of the GPIO within the function. - flags is defined to specify the following properties: * GPIOF_ACTIVE_LOW - to configure the GPIO as active-low @@ -86,18 +87,23 @@ In the future, these flags might be extended to support more properties. Note that GPIO_LOOKUP() is just a shortcut to GPIO_LOOKUP_IDX() where idx = 0. -A lookup table can then be defined as follows: +A lookup table can then be defined as follows, with an empty entry defining its +end: - struct gpiod_lookup gpios_table[] = { - GPIO_LOOKUP_IDX("gpio.0", 15, "foo.0", "led", 0, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("gpio.0", 16, "foo.0", "led", 1, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP_IDX("gpio.0", 17, "foo.0", "led", 2, GPIO_ACTIVE_HIGH), - GPIO_LOOKUP("gpio.0", 1, "foo.0", "power", GPIO_ACTIVE_LOW), - }; +struct gpiod_lookup_table gpios_table = { + .dev_id = "foo.0", + .table = { + GPIO_LOOKUP_IDX("gpio.0", 15, "led", 0, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio.0", 16, "led", 1, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP_IDX("gpio.0", 17, "led", 2, GPIO_ACTIVE_HIGH), + GPIO_LOOKUP("gpio.0", 1, "power", GPIO_ACTIVE_LOW), + { }, + }, +}; And the table can be added by the board code as follows: - gpiod_add_table(gpios_table, ARRAY_SIZE(gpios_table)); + gpiod_add_lookup_table(&gpios_table); The driver controlling "foo.0" will then be able to obtain its GPIOs as follows: diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 44a232701179..4eb262a31777 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2260,18 +2260,14 @@ void gpiod_set_value_cansleep(struct gpio_desc *desc, int value) EXPORT_SYMBOL_GPL(gpiod_set_value_cansleep); /** - * gpiod_add_table() - register GPIO device consumers - * @table: array of consumers to register - * @num: number of consumers in table + * gpiod_add_lookup_table() - register GPIO device consumers + * @table: table of consumers to register */ -void gpiod_add_table(struct gpiod_lookup *table, size_t size) +void gpiod_add_lookup_table(struct gpiod_lookup_table *table) { mutex_lock(&gpio_lookup_lock); - while (size--) { - list_add_tail(&table->list, &gpio_lookup_list); - table++; - } + list_add_tail(&table->list, &gpio_lookup_list); mutex_unlock(&gpio_lookup_lock); } @@ -2327,72 +2323,84 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id, return desc; } -static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, - unsigned int idx, - enum gpio_lookup_flags *flags) +static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev) { const char *dev_id = dev ? dev_name(dev) : NULL; - struct gpio_desc *desc = ERR_PTR(-ENODEV); - unsigned int match, best = 0; - struct gpiod_lookup *p; + struct gpiod_lookup_table *table; mutex_lock(&gpio_lookup_lock); - list_for_each_entry(p, &gpio_lookup_list, list) { - match = 0; + list_for_each_entry(table, &gpio_lookup_list, list) { + if (table->dev_id && dev_id) { + /* + * Valid strings on both ends, must be identical to have + * a match + */ + if (!strcmp(table->dev_id, dev_id)) + goto found; + } else { + /* + * One of the pointers is NULL, so both must be to have + * a match + */ + if (dev_id == table->dev_id) + goto found; + } + } + table = NULL; - if (p->dev_id) { - if (!dev_id || strcmp(p->dev_id, dev_id)) - continue; +found: + mutex_unlock(&gpio_lookup_lock); + return table; +} - match += 2; - } +static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id, + unsigned int idx, + enum gpio_lookup_flags *flags) +{ + struct gpio_desc *desc = ERR_PTR(-ENODEV); + struct gpiod_lookup_table *table; + struct gpiod_lookup *p; - if (p->con_id) { - if (!con_id || strcmp(p->con_id, con_id)) - continue; + table = gpiod_find_lookup_table(dev); + if (!table) + return desc; - match += 1; - } + for (p = &table->table[0]; p->chip_label; p++) { + struct gpio_chip *chip; + /* idx must always match exactly */ if (p->idx != idx) continue; - if (match > best) { - struct gpio_chip *chip; - - chip = find_chip_by_name(p->chip_label); - - if (!chip) { - dev_warn(dev, "cannot find GPIO chip %s\n", - p->chip_label); - continue; - } + /* If the lookup entry has a con_id, require exact match */ + if (p->con_id && (!con_id || strcmp(p->con_id, con_id))) + continue; - if (chip->ngpio <= p->chip_hwnum) { - dev_warn(dev, "GPIO chip %s has %d GPIOs\n", - chip->label, chip->ngpio); - continue; - } + chip = find_chip_by_name(p->chip_label); - desc = gpio_to_desc(chip->base + p->chip_hwnum); - *flags = p->flags; + if (!chip) { + dev_warn(dev, "cannot find GPIO chip %s\n", + p->chip_label); + continue; + } - if (match != 3) - best = match; - else - break; + if (chip->ngpio <= p->chip_hwnum) { + dev_warn(dev, "GPIO chip %s has %d GPIOs\n", + chip->label, chip->ngpio); + continue; } - } - mutex_unlock(&gpio_lookup_lock); + desc = gpiochip_offset_to_desc(chip, p->chip_hwnum); + *flags = p->flags; + } return desc; } /** * gpio_get - obtain a GPIO for a given GPIO function - * @dev: GPIO consumer + * @dev: GPIO consumer, can be NULL for system-global GPIOs * @con_id: function within the GPIO consumer * * Return the GPIO descriptor corresponding to the function con_id of device diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index c849676c6787..44c66b29a2d9 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -141,7 +141,6 @@ enum gpio_lookup_flags { * platform data. */ struct gpiod_lookup { - struct list_head list; /* * name of the chip the GPIO belongs to */ @@ -150,10 +149,6 @@ struct gpiod_lookup { * hardware number (i.e. relative to the chip) of the GPIO */ u16 chip_hwnum; - /* - * name of device that can claim this GPIO - */ - const char *dev_id; /* * name of the GPIO from the device's point of view */ @@ -168,28 +163,32 @@ struct gpiod_lookup { enum gpio_lookup_flags flags; }; +struct gpiod_lookup_table { + struct list_head list; + const char *dev_id; + struct gpiod_lookup table[]; +}; + /* * Simple definition of a single GPIO under a con_id */ -#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _dev_id, _con_id, _flags) \ - GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, 0, _flags) +#define GPIO_LOOKUP(_chip_label, _chip_hwnum, _con_id, _flags) \ + GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, 0, _flags) /* * Use this macro if you need to have several GPIOs under the same con_id. * Each GPIO needs to use a different index and can be accessed using * gpiod_get_index() */ -#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _dev_id, _con_id, _idx, \ - _flags) \ +#define GPIO_LOOKUP_IDX(_chip_label, _chip_hwnum, _con_id, _idx, _flags) \ { \ .chip_label = _chip_label, \ .chip_hwnum = _chip_hwnum, \ - .dev_id = _dev_id, \ .con_id = _con_id, \ .idx = _idx, \ .flags = _flags, \ } -void gpiod_add_table(struct gpiod_lookup *table, size_t size); +void gpiod_add_lookup_table(struct gpiod_lookup_table *table); #endif -- cgit v1.2.3-59-g8ed1b From f9244ae5dce18b73ac42f5979116050da3a5c4d5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 5 Dec 2013 11:26:25 +0200 Subject: gpiolib: convert gpiod_lookup description to kernel-doc The patch moves description of the fields to the top of struct definition and converts them to the kernel-doc format. There is no functional change. Signed-off-by: Andy Shevchenko Acked-by: Alexandre Courbot Reviewed-by: Mika Westerberg Signed-off-by: Linus Walleij --- include/linux/gpio/driver.h | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 44c66b29a2d9..a3e181e09636 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -137,29 +137,21 @@ enum gpio_lookup_flags { }; /** - * Lookup table for associating GPIOs to specific devices and functions using - * platform data. + * struct gpiod_lookup - lookup table + * @chip_label: name of the chip the GPIO belongs to + * @chip_hwnum: hardware number (i.e. relative to the chip) of the GPIO + * @con_id: name of the GPIO from the device's point of view + * @idx: index of the GPIO in case several GPIOs share the same name + * @flags: mask of GPIO_* values + * + * gpiod_lookup is a lookup table for associating GPIOs to specific devices and + * functions using platform data. */ struct gpiod_lookup { - /* - * name of the chip the GPIO belongs to - */ const char *chip_label; - /* - * hardware number (i.e. relative to the chip) of the GPIO - */ u16 chip_hwnum; - /* - * name of the GPIO from the device's point of view - */ const char *con_id; - /* - * index of the GPIO in case several GPIOs share the same name - */ unsigned int idx; - /* - * mask of GPIO_* values - */ enum gpio_lookup_flags flags; }; -- cgit v1.2.3-59-g8ed1b From acc0f67f307f52f7aec1cffdc40a786c15dd21d9 Mon Sep 17 00:00:00 2001 From: Peter Hurley Date: Mon, 9 Dec 2013 09:23:52 -0500 Subject: tty: Halve flip buffer GFP_ATOMIC memory consumption tty flip buffers use GFP_ATOMIC allocations for received data which is to be processed by the line discipline. For each byte received, an extra byte is used to indicate the error status of that byte. Instead, if the received data is error-free, encode the entire buffer without status bytes. Signed-off-by: Peter Hurley Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 45 +++++++++++++++++++++++++++++++++++---------- include/linux/tty.h | 4 ++++ include/linux/tty_flip.h | 8 ++++++-- 3 files changed, 45 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 08835a6dd022..3002e20e10d7 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -101,6 +101,7 @@ static void tty_buffer_reset(struct tty_buffer *p, size_t size) p->next = NULL; p->commit = 0; p->read = 0; + p->flags = 0; } /** @@ -229,31 +230,49 @@ void tty_buffer_flush(struct tty_struct *tty) * tty_buffer_request_room - grow tty buffer if needed * @tty: tty structure * @size: size desired + * @flags: buffer flags if new buffer allocated (default = 0) * * Make at least size bytes of linear space available for the tty * buffer. If we fail return the size we managed to find. + * + * Will change over to a new buffer if the current buffer is encoded as + * TTY_NORMAL (so has no flags buffer) and the new buffer requires + * a flags buffer. */ -int tty_buffer_request_room(struct tty_port *port, size_t size) +static int __tty_buffer_request_room(struct tty_port *port, size_t size, + int flags) { struct tty_bufhead *buf = &port->buf; struct tty_buffer *b, *n; - int left; + int left, change; b = buf->tail; - left = b->size - b->used; + if (b->flags & TTYB_NORMAL) + left = 2 * b->size - b->used; + else + left = b->size - b->used; - if (left < size) { + change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL); + if (change || left < size) { /* This is the slow path - looking for new buffers to use */ if ((n = tty_buffer_alloc(port, size)) != NULL) { + n->flags = flags; buf->tail = n; b->commit = b->used; smp_mb(); b->next = n; - } else + } else if (change) + size = 0; + else size = left; } return size; } + +int tty_buffer_request_room(struct tty_port *port, size_t size) +{ + return __tty_buffer_request_room(port, size, 0); +} EXPORT_SYMBOL_GPL(tty_buffer_request_room); /** @@ -273,12 +292,14 @@ int tty_insert_flip_string_fixed_flag(struct tty_port *port, int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); - int space = tty_buffer_request_room(port, goal); + int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; + int space = __tty_buffer_request_room(port, goal, flags); struct tty_buffer *tb = port->buf.tail; if (unlikely(space == 0)) break; memcpy(char_buf_ptr(tb, tb->used), chars, space); - memset(flag_buf_ptr(tb, tb->used), flag, space); + if (~tb->flags & TTYB_NORMAL) + memset(flag_buf_ptr(tb, tb->used), flag, space); tb->used += space; copied += space; chars += space; @@ -361,11 +382,12 @@ EXPORT_SYMBOL(tty_schedule_flip); int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, size_t size) { - int space = tty_buffer_request_room(port, size); + int space = __tty_buffer_request_room(port, size, TTYB_NORMAL); if (likely(space)) { struct tty_buffer *tb = port->buf.tail; *chars = char_buf_ptr(tb, tb->used); - memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space); + if (~tb->flags & TTYB_NORMAL) + memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space); tb->used += space; } return space; @@ -378,7 +400,10 @@ receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count) { struct tty_ldisc *disc = tty->ldisc; unsigned char *p = char_buf_ptr(head, head->read); - char *f = flag_buf_ptr(head, head->read); + char *f = NULL; + + if (~head->flags & TTYB_NORMAL) + f = flag_buf_ptr(head, head->read); if (disc->ops->receive_buf2) count = disc->ops->receive_buf2(tty, p, f, count); diff --git a/include/linux/tty.h b/include/linux/tty.h index 38fcc0574ba9..ad98b4376968 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -39,10 +39,14 @@ struct tty_buffer { int size; int commit; int read; + int flags; /* Data points here */ unsigned long data[0]; }; +/* Values for .flags field of tty_buffer */ +#define TTYB_NORMAL 1 /* buffer has no flags buffer */ + static inline unsigned char *char_buf_ptr(struct tty_buffer *b, int ofs) { return ((unsigned char *)b->data) + ofs; diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h index 3f821e98af0f..c28dd523f96e 100644 --- a/include/linux/tty_flip.h +++ b/include/linux/tty_flip.h @@ -17,8 +17,12 @@ static inline int tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag) { struct tty_buffer *tb = port->buf.tail; - if (tb && tb->used < tb->size) { - *flag_buf_ptr(tb, tb->used) = flag; + int change; + + change = (tb->flags & TTYB_NORMAL) && (flag != TTY_NORMAL); + if (!change && tb->used < tb->size) { + if (~tb->flags & TTYB_NORMAL) + *flag_buf_ptr(tb, tb->used) = flag; *char_buf_ptr(tb, tb->used++) = ch; return 1; } -- cgit v1.2.3-59-g8ed1b From 0f978bfaf2600040f9826f394eb12e023bef3068 Mon Sep 17 00:00:00 2001 From: Sujith Manoharan Date: Fri, 6 Dec 2013 16:28:45 +0530 Subject: ath9k: Use a separate TX gain table for WZR-HP-G450H The Buffalo device WZR-HP-G450H uses the index 3 for TX gain, which is set to the high_power table currently. Later variants of the router use the same index, but instead refer to the low_ob_db gain table. This is not handled in the driver since there is no way to distinguish board revisions and the high_power table is used (incorrectly) for the newer variants. By default, devices based on AR9300 using the TX gain index 3 have to use the high_power table. To make sure that WZR-HP-G450H is not broken when the high_power table is updated, use a separate array based on information obtained from the platform data. The current situation where only the original variant of WZR-HP-G450H works properly stays unchanged. Signed-off-by: Sujith Manoharan Signed-off-by: John W. Linville --- .../wireless/ath/ath9k/ar9003_buffalo_initvals.h | 126 +++++++++++++++++++++ drivers/net/wireless/ath/ath9k/ar9003_hw.c | 12 +- drivers/net/wireless/ath/ath9k/hw.h | 1 + drivers/net/wireless/ath/ath9k/init.c | 36 ++++-- include/linux/ath9k_platform.h | 2 + 5 files changed, 165 insertions(+), 12 deletions(-) create mode 100644 drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h (limited to 'include/linux') diff --git a/drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h new file mode 100644 index 000000000000..59cf738f70df --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar9003_buffalo_initvals.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2013 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_9003_BUFFALO_H +#define INITVALS_9003_BUFFALO_H + +static const u32 ar9300Modes_high_power_tx_gain_table_buffalo[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, + {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, + {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, + {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, + {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, + {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, + {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, + {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, + {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, + {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, + {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, + {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, + {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, + {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, + {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, +}; + +#endif /* INITVALS_9003_BUFFALO_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 4e8ae4a79dc0..29613ebbc5d7 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -17,6 +17,7 @@ #include "hw.h" #include "ar9003_mac.h" #include "ar9003_2p2_initvals.h" +#include "ar9003_buffalo_initvals.h" #include "ar9485_initvals.h" #include "ar9340_initvals.h" #include "ar9330_1p1_initvals.h" @@ -592,9 +593,14 @@ static void ar9003_tx_gain_table_mode3(struct ath_hw *ah) else if (AR_SREV_9565(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9565_1p0_modes_high_power_tx_gain_table); - else - INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_high_power_tx_gain_table_2p2); + else { + if (ah->config.tx_gain_buffalo) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_high_power_tx_gain_table_buffalo); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9300Modes_high_power_tx_gain_table_2p2); + } } static void ar9003_tx_gain_table_mode4(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 7490047acd11..b1ff54631dca 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -316,6 +316,7 @@ struct ath9k_ops_config { bool xatten_margin_cfg; bool alt_mingainidx; bool no_pll_pwrsave; + bool tx_gain_buffalo; }; enum ath9k_int { diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 5a0b7e82c85f..609b7e13f3f0 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -554,7 +554,7 @@ static void ath9k_init_misc(struct ath_softc *sc) sc->spec_config.fft_period = 0xF; } -static void ath9k_init_platform(struct ath_softc *sc) +static void ath9k_init_pcoem_platform(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath9k_hw_capabilities *pCap = &ah->caps; @@ -664,6 +664,27 @@ static void ath9k_eeprom_release(struct ath_softc *sc) release_firmware(sc->sc_ah->eeprom_blob); } +static int ath9k_init_soc_platform(struct ath_softc *sc) +{ + struct ath9k_platform_data *pdata = sc->dev->platform_data; + struct ath_hw *ah = sc->sc_ah; + int ret = 0; + + if (!pdata) + return 0; + + if (pdata->eeprom_name) { + ret = ath9k_eeprom_request(sc, pdata->eeprom_name); + if (ret) + return ret; + } + + if (pdata->tx_gain_buffalo) + ah->config.tx_gain_buffalo = true; + + return ret; +} + static int ath9k_init_softc(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops) { @@ -717,7 +738,11 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, /* * Platform quirks. */ - ath9k_init_platform(sc); + ath9k_init_pcoem_platform(sc); + + ret = ath9k_init_soc_platform(sc); + if (ret) + return ret; /* * Enable WLAN/BT RX Antenna diversity only when: @@ -731,7 +756,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, common->bt_ant_diversity = 1; spin_lock_init(&common->cc_lock); - spin_lock_init(&sc->sc_serial_rw); spin_lock_init(&sc->sc_pm_lock); mutex_init(&sc->mutex); @@ -753,12 +777,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ath_read_cachesize(common, &csz); common->cachelsz = csz << 2; /* convert to bytes */ - if (pdata && pdata->eeprom_name) { - ret = ath9k_eeprom_request(sc, pdata->eeprom_name); - if (ret) - return ret; - } - /* Initializes the hardware for all supported chipsets */ ret = ath9k_hw_init(ah); if (ret) diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h index fcdd81bd5314..8598f8eacb20 100644 --- a/include/linux/ath9k_platform.h +++ b/include/linux/ath9k_platform.h @@ -32,6 +32,8 @@ struct ath9k_platform_data { u32 gpio_val; bool is_clk_25mhz; + bool tx_gain_buffalo; + int (*get_mac_revision)(void); int (*external_reset)(void); }; -- cgit v1.2.3-59-g8ed1b From 24ef659a857c3cba40b64ea51ea4fce8d2fb7bbc Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 28 Oct 2013 09:22:24 -0700 Subject: rcu: Provide better diagnostics for blocking in RCU callback functions Currently blocking in an RCU callback function will result in "scheduling while atomic", which could be triggered for any number of reasons. To aid debugging, this patch introduces a rcu_callback_map that is used to tie the inappropriate voluntary context switch back to the fact that the function is being invoked from within a callback. Signed-off-by: Paul E. McKenney --- include/linux/rcupdate.h | 1 + kernel/rcu/rcu.h | 3 +++ kernel/rcu/update.c | 5 +++++ 3 files changed, 9 insertions(+) (limited to 'include/linux') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 39cbb889e20d..a94a5805d378 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -325,6 +325,7 @@ static inline void rcu_lock_release(struct lockdep_map *map) extern struct lockdep_map rcu_lock_map; extern struct lockdep_map rcu_bh_lock_map; extern struct lockdep_map rcu_sched_lock_map; +extern struct lockdep_map rcu_callback_map; extern int debug_lockdep_rcu_enabled(void); /** diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h index 7859a0a3951e..a8f981a2d110 100644 --- a/kernel/rcu/rcu.h +++ b/kernel/rcu/rcu.h @@ -102,13 +102,16 @@ static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head) { unsigned long offset = (unsigned long)head->func; + rcu_lock_acquire(&rcu_callback_map); if (__is_kfree_rcu_offset(offset)) { RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset)); kfree((void *)head - offset); + rcu_lock_release(&rcu_callback_map); return 1; } else { RCU_TRACE(trace_rcu_invoke_callback(rn, head)); head->func(head); + rcu_lock_release(&rcu_callback_map); return 0; } } diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index 6cb3dff89e2b..802365ccd591 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c @@ -128,6 +128,11 @@ struct lockdep_map rcu_sched_lock_map = STATIC_LOCKDEP_MAP_INIT("rcu_read_lock_sched", &rcu_sched_lock_key); EXPORT_SYMBOL_GPL(rcu_sched_lock_map); +static struct lock_class_key rcu_callback_key; +struct lockdep_map rcu_callback_map = + STATIC_LOCKDEP_MAP_INIT("rcu_callback", &rcu_callback_key); +EXPORT_SYMBOL_GPL(rcu_callback_map); + int notrace debug_lockdep_rcu_enabled(void) { return rcu_scheduler_active && debug_locks && -- cgit v1.2.3-59-g8ed1b From 4262e5ccbbb5171abd2921eed16ed339633d6478 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 6 Dec 2013 11:36:16 +0100 Subject: net: dev: move inline skb_needs_linearize helper to header As we need it elsewhere, move the inline helper function of skb_needs_linearize() over to skbuff.h include file. While at it, also convert the return to 'bool' instead of 'int' and add a proper kernel doc. Signed-off-by: Daniel Borkmann Signed-off-by: Jesper Dangaard Brouer Signed-off-by: David S. Miller --- include/linux/skbuff.h | 18 ++++++++++++++++++ net/core/dev.c | 15 --------------- 2 files changed, 18 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 215b5ea1cb30..77c7aae1c6b2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2392,6 +2392,24 @@ static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, return buffer; } +/** + * skb_needs_linearize - check if we need to linearize a given skb + * depending on the given device features. + * @skb: socket buffer to check + * @features: net device features + * + * Returns true if either: + * 1. skb has frag_list and the device doesn't support FRAGLIST, or + * 2. skb is fragmented and the device does not support SG. + */ +static inline bool skb_needs_linearize(struct sk_buff *skb, + netdev_features_t features) +{ + return skb_is_nonlinear(skb) && + ((skb_has_frag_list(skb) && !(features & NETIF_F_FRAGLIST)) || + (skb_shinfo(skb)->nr_frags && !(features & NETIF_F_SG))); +} + static inline void skb_copy_from_linear_data(const struct sk_buff *skb, void *to, const unsigned int len) diff --git a/net/core/dev.c b/net/core/dev.c index 6cc98dd49c7a..355df36360b4 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2535,21 +2535,6 @@ netdev_features_t netif_skb_features(struct sk_buff *skb) } EXPORT_SYMBOL(netif_skb_features); -/* - * Returns true if either: - * 1. skb has frag_list and the device doesn't support FRAGLIST, or - * 2. skb is fragmented and the device does not support SG. - */ -static inline int skb_needs_linearize(struct sk_buff *skb, - netdev_features_t features) -{ - return skb_is_nonlinear(skb) && - ((skb_has_frag_list(skb) && - !(features & NETIF_F_FRAGLIST)) || - (skb_shinfo(skb)->nr_frags && - !(features & NETIF_F_SG))); -} - int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq, void *accel_priv) { -- cgit v1.2.3-59-g8ed1b From 114002bc1af6c63de4c003f8c5d3ca0bb430d987 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 6 Dec 2013 13:01:30 -0800 Subject: net: phy: report link partner features through ethtool The PHY library already reads the MII_STAT1000 and MII_LPA registers in genphy_read_status(), so extend it to also populate the PHY device link partner advertised features such that we can feed this back into ethtool when asked for it in phy_ethtool_gset(). Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 1 + drivers/net/phy/phy_device.c | 6 ++++++ include/linux/phy.h | 5 +++-- 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 36c6994436b7..05cb8fe742f9 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -289,6 +289,7 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) cmd->supported = phydev->supported; cmd->advertising = phydev->advertising; + cmd->lp_advertising = phydev->lp_advertising; ethtool_cmd_speed_set(cmd, phydev->speed); cmd->duplex = phydev->duplex; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index d6447b3f7409..6db36595eac9 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -839,6 +839,8 @@ int genphy_read_status(struct phy_device *phydev) if (err) return err; + phydev->lp_advertising = 0; + if (AUTONEG_ENABLE == phydev->autoneg) { if (phydev->supported & (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)) { @@ -852,6 +854,8 @@ int genphy_read_status(struct phy_device *phydev) if (adv < 0) return adv; + phydev->lp_advertising = + mii_stat1000_to_ethtool_lpa_t(lpagb); lpagb &= adv << 2; } @@ -860,6 +864,8 @@ int genphy_read_status(struct phy_device *phydev) if (lpa < 0) return lpa; + phydev->lp_advertising |= mii_lpa_to_ethtool_lpa_t(lpa); + adv = phy_read(phydev, MII_ADVERTISE); if (adv < 0) diff --git a/include/linux/phy.h b/include/linux/phy.h index 7ff751ae6f0a..90a666e0884b 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -287,8 +287,8 @@ struct phy_c45_device_ids { * adjust_state: Callback for the enet driver to respond to * changes in the state machine. * - * speed, duplex, pause, supported, advertising, and - * autoneg are used like in mii_if_info + * speed, duplex, pause, supported, advertising, lp_advertising, + * and autoneg are used like in mii_if_info * * interrupts currently only supports enabled or disabled, * but could be changed in the future to support enabling @@ -340,6 +340,7 @@ struct phy_device { /* See mii.h for more info */ u32 supported; u32 advertising; + u32 lp_advertising; int autoneg; -- cgit v1.2.3-59-g8ed1b From 1d4c8c29841b9991cdf3c7cc4ba7f96a94f104ca Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sat, 7 Dec 2013 19:26:56 +0100 Subject: neigh: restore old behaviour of default parms values Previously inet devices were only constructed when addresses are added. Therefore the default neigh parms values they get are the ones at the time of these operations. Now that we're creating inet devices earlier, this changes the behaviour of default neigh parms values in an incompatible way (see bug #8519). This patch creates a compromise by setting the default values at the same point as before but only for those that have not been explicitly set by the user since the inet device's creation. Introduced by: commit 8030f54499925d073a88c09f30d5d844fb1b3190 Author: Herbert Xu Date: Thu Feb 22 01:53:47 2007 +0900 [IPV4] devinet: Register inetdev earlier. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 7 +++++ include/net/neighbour.h | 13 ++++++++ net/core/neighbour.c | 74 ++++++++++++++++++++++++++++++++++++++++++---- net/ipv4/devinet.c | 2 ++ net/ipv4/ipmr.c | 2 ++ 5 files changed, 92 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 0d678aefe69d..ae174ca565c9 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -220,6 +220,13 @@ static inline struct in_device *__in_dev_get_rtnl(const struct net_device *dev) return rtnl_dereference(dev->ip_ptr); } +static inline struct neigh_parms *__in_dev_arp_parms_get_rcu(const struct net_device *dev) +{ + struct in_device *in_dev = __in_dev_get_rcu(dev); + + return in_dev ? in_dev->arp_parms : NULL; +} + void in_dev_finish_destroy(struct in_device *idev); static inline void in_dev_put(struct in_device *idev) diff --git a/include/net/neighbour.h b/include/net/neighbour.h index 95615c9ad13a..41b1ce6c96a8 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -81,16 +82,28 @@ struct neigh_parms { int reachable_time; int data[NEIGH_VAR_DATA_MAX]; + DECLARE_BITMAP(data_state, NEIGH_VAR_DATA_MAX); }; static inline void neigh_var_set(struct neigh_parms *p, int index, int val) { + set_bit(index, p->data_state); p->data[index] = val; } #define NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr]) #define NEIGH_VAR_SET(p, attr, val) neigh_var_set(p, NEIGH_VAR_ ## attr, val) +static inline void neigh_parms_data_state_setall(struct neigh_parms *p) +{ + bitmap_fill(p->data_state, NEIGH_VAR_DATA_MAX); +} + +static inline void neigh_parms_data_state_cleanall(struct neigh_parms *p) +{ + bitmap_zero(p->data_state, NEIGH_VAR_DATA_MAX); +} + struct neigh_statistics { unsigned long allocs; /* number of allocated neighs */ unsigned long destroys; /* number of destroyed neighs */ diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 65ead080167b..c4a7879bfb15 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -38,6 +38,7 @@ #include #include #include +#include #define DEBUG #define NEIGH_DEBUG 1 @@ -1464,6 +1465,8 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, p->next = tbl->parms.next; tbl->parms.next = p; write_unlock_bh(&tbl->lock); + + neigh_parms_data_state_cleanall(p); } return p; } @@ -2813,22 +2816,68 @@ static int proc_unres_qlen(struct ctl_table *ctl, int write, return ret; } +static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev, + int family) +{ + if (family == AF_INET) + return __in_dev_arp_parms_get_rcu(dev); + return NULL; +} + +static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p, + int index) +{ + struct net_device *dev; + int family = neigh_parms_family(p); + + rcu_read_lock(); + for_each_netdev_rcu(net, dev) { + struct neigh_parms *dst_p = + neigh_get_dev_parms_rcu(dev, family); + + if (dst_p && !test_bit(index, dst_p->data_state)) + dst_p->data[index] = p->data[index]; + } + rcu_read_unlock(); +} + +static void neigh_proc_update(struct ctl_table *ctl, int write) +{ + struct net_device *dev = ctl->extra1; + struct neigh_parms *p = ctl->extra2; + struct net *net = p->net; + int index = (int *) ctl->data - p->data; + + if (!write) + return; + + set_bit(index, p->data_state); + if (!dev) /* NULL dev means this is default value */ + neigh_copy_dflt_parms(net, p, index); +} + static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { struct ctl_table tmp = *ctl; + int ret; tmp.extra1 = &zero; tmp.extra2 = &int_max; - return proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); + ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); + neigh_proc_update(ctl, write); + return ret; } int neigh_proc_dointvec(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - return proc_dointvec(ctl, write, buffer, lenp, ppos); + int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); + + neigh_proc_update(ctl, write); + return ret; } EXPORT_SYMBOL(neigh_proc_dointvec); @@ -2836,7 +2885,10 @@ int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - return proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); + int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); + + neigh_proc_update(ctl, write); + return ret; } EXPORT_SYMBOL(neigh_proc_dointvec_jiffies); @@ -2844,14 +2896,20 @@ static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - return proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos); + int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos); + + neigh_proc_update(ctl, write); + return ret; } int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - return proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos); + int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos); + + neigh_proc_update(ctl, write); + return ret; } EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies); @@ -2859,7 +2917,10 @@ static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { - return proc_unres_qlen(ctl, write, buffer, lenp, ppos); + int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos); + + neigh_proc_update(ctl, write); + return ret; } #define NEIGH_PARMS_DATA_OFFSET(index) \ @@ -2962,6 +3023,7 @@ int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) { t->neigh_vars[i].data += (long) p; t->neigh_vars[i].extra1 = dev; + t->neigh_vars[i].extra2 = p; } if (dev) { diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index e1c19535fe38..43065be36301 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -500,6 +500,7 @@ static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) return -ENOBUFS; } ipv4_devconf_setall(in_dev); + neigh_parms_data_state_setall(in_dev->arp_parms); if (ifa->ifa_dev != in_dev) { WARN_ON(ifa->ifa_dev); in_dev_hold(in_dev); @@ -747,6 +748,7 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, goto errout; ipv4_devconf_setall(in_dev); + neigh_parms_data_state_setall(in_dev->arp_parms); in_dev_hold(in_dev); if (tb[IFA_ADDRESS] == NULL) diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 62212c772a4b..421a24934ffd 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -425,6 +425,7 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v) goto failure; ipv4_devconf_setall(in_dev); + neigh_parms_data_state_setall(in_dev->arp_parms); IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; if (dev_open(dev)) @@ -517,6 +518,7 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt) } ipv4_devconf_setall(in_dev); + neigh_parms_data_state_setall(in_dev->arp_parms); IPV4_DEVCONF(in_dev->cnf, RP_FILTER) = 0; rcu_read_unlock(); -- cgit v1.2.3-59-g8ed1b From 73eaef87e98a96fe8b8a586f916b2721bf512efa Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 6 Dec 2013 14:21:01 -0800 Subject: etherdevice: Add ether_addr_equal_unaligned Add a generic routine to test if possibly unaligned to u16 Ethernet addresses are equal. If CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is set, this uses the slightly faster generic routine ether_addr_equal, otherwise this uses memcmp. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- include/linux/etherdevice.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'include/linux') diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 3526e819d7ae..2f0e3d0818bc 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -265,6 +265,24 @@ static inline bool ether_addr_equal_64bits(const u8 addr1[6+2], #endif } +/** + * ether_addr_equal_unaligned - Compare two not u16 aligned Ethernet addresses + * @addr1: Pointer to a six-byte array containing the Ethernet address + * @addr2: Pointer other six-byte array containing the Ethernet address + * + * Compare two Ethernet addresses, returns true if equal + * + * Please note: Use only when any Ethernet address may not be u16 aligned. + */ +static inline bool ether_addr_equal_unaligned(const u8 *addr1, const u8 *addr2) +{ +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + return ether_addr_equal(addr1, addr2); +#else + return memcmp(addr1, addr2, ETH_ALEN) == 0; +#endif +} + /** * is_etherdev_addr - Tell if given Ethernet address belongs to the device. * @dev: Pointer to a device structure -- cgit v1.2.3-59-g8ed1b From 2c722fe1c821a100ca87fcc36e90a9bceb497c7c Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 6 Dec 2013 15:44:21 -0800 Subject: etherdevice: Optimize a few is__ether_addr functions If CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is set, several is__ether_addr functions can be slightly improved by using u32 dereferences. I believe all current uses of is_zero_ether_addr and is_broadcast_ether_addr are u16 aligned, so always use u16 references to improve those functions performance. Document the u16 alignment requirements. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- include/linux/etherdevice.h | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 2f0e3d0818bc..f344ac04f858 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -61,6 +61,8 @@ static const u8 eth_reserved_addr_base[ETH_ALEN] __aligned(2) = * * Return true if address is link local reserved addr (01:80:c2:00:00:0X) per * IEEE 802.1Q 8.6.3 Frame filtering. + * + * Please note: addr must be aligned to u16. */ static inline bool is_link_local_ether_addr(const u8 *addr) { @@ -68,7 +70,12 @@ static inline bool is_link_local_ether_addr(const u8 *addr) static const __be16 *b = (const __be16 *)eth_reserved_addr_base; static const __be16 m = cpu_to_be16(0xfff0); +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + return (((*(const u32 *)addr) ^ (*(const u32 *)b)) | + ((a[2] ^ b[2]) & m)) == 0; +#else return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0; +#endif } /** @@ -76,10 +83,18 @@ static inline bool is_link_local_ether_addr(const u8 *addr) * @addr: Pointer to a six-byte array containing the Ethernet address * * Return true if the address is all zeroes. + * + * Please note: addr must be aligned to u16. */ static inline bool is_zero_ether_addr(const u8 *addr) { - return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]); +#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) + return ((*(const u32 *)addr) | (*(const u16 *)(addr + 4))) == 0; +#else + return (*(const u16 *)(addr + 0) | + *(const u16 *)(addr + 2) | + *(const u16 *)(addr + 4)) == 0; +#endif } /** @@ -110,10 +125,14 @@ static inline bool is_local_ether_addr(const u8 *addr) * @addr: Pointer to a six-byte array containing the Ethernet address * * Return true if the address is the broadcast address. + * + * Please note: addr must be aligned to u16. */ static inline bool is_broadcast_ether_addr(const u8 *addr) { - return (addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5]) == 0xff; + return (*(const u16 *)(addr + 0) & + *(const u16 *)(addr + 2) & + *(const u16 *)(addr + 4)) == 0xffff; } /** @@ -135,6 +154,8 @@ static inline bool is_unicast_ether_addr(const u8 *addr) * a multicast address, and is not FF:FF:FF:FF:FF:FF. * * Return true if the address is valid. + * + * Please note: addr must be aligned to u16. */ static inline bool is_valid_ether_addr(const u8 *addr) { -- cgit v1.2.3-59-g8ed1b From 1397ed35f22d7c30d0b89ba74b6b7829220dfcfd Mon Sep 17 00:00:00 2001 From: Florent Fourcot Date: Sun, 8 Dec 2013 15:46:57 +0100 Subject: ipv6: add flowinfo for tcp6 pkt_options for all cases The current implementation of IPV6_FLOWINFO only gives a result if pktoptions is available (thanks to the ip6_datagram_recv_ctl function). It gives inconsistent results to user space, sometimes there is a result for getsockopt(IPV6_FLOWINFO), sometimes not. This patch add rcv_flowinfo to store it, and return it to the userspace in the same way than other pkt_options. Signed-off-by: Florent Fourcot Reviewed-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/linux/ipv6.h | 1 + net/ipv6/ipv6_sockglue.c | 4 ++++ net/ipv6/tcp_ipv6.c | 4 ++++ 3 files changed, 9 insertions(+) (limited to 'include/linux') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index c56c350324e4..0b2ebfbbe0f4 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -201,6 +201,7 @@ struct ipv6_pinfo { __u8 min_hopcount; __u8 tclass; __u8 rcv_tclass; + __be32 rcv_flowinfo; __u32 dst_cookie; __u32 rx_dst_cookie; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 1c6ce3119ff8..c2db1df46385 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -1034,6 +1034,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, int hlim = np->mcast_hops; put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim); } + if (np->rxopt.bits.rxflow) { + int flowinfo = np->rcv_flowinfo; + put_cmsg(&msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); + } } len -= msg.msg_controllen; return put_user(len, optlen); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 0740f93a114a..79a196369558 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1136,6 +1136,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); + newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); /* * No need to charge this sock to the relevant IPv6 refcnt debug socks count @@ -1216,6 +1217,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); + newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); /* Clone native IPv6 options from listening socket (if any) @@ -1427,6 +1429,8 @@ ipv6_pktoptions: np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; if (np->rxopt.bits.rxtclass) np->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(opt_skb)); + if (np->rxopt.bits.rxflow) + np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); if (ipv6_opt_accepted(sk, opt_skb)) { skb_set_owner_r(opt_skb, sk); opt_skb = xchg(&np->pktoptions, opt_skb); -- cgit v1.2.3-59-g8ed1b From 82e9f105a28006e7ff864220a28cf62ea6d1e280 Mon Sep 17 00:00:00 2001 From: Florent Fourcot Date: Sun, 8 Dec 2013 15:46:59 +0100 Subject: ipv6: remove rcv_tclass of ipv6_pinfo tclass information in now already stored in rcv_flowinfo We do not need to store the same information twice. Signed-off-by: Florent Fourcot Reviewed-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/linux/ipv6.h | 1 - net/ipv6/ipv6_sockglue.c | 2 +- net/ipv6/tcp_ipv6.c | 6 +----- 3 files changed, 2 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 0b2ebfbbe0f4..3fde06645553 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -200,7 +200,6 @@ struct ipv6_pinfo { dontfrag:1; __u8 min_hopcount; __u8 tclass; - __u8 rcv_tclass; __be32 rcv_flowinfo; __u32 dst_cookie; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index c2db1df46385..7d9391506856 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -1019,7 +1019,7 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); } if (np->rxopt.bits.rxtclass) { - int tclass = np->rcv_tclass; + int tclass = ntohl(np->rcv_flowinfo & IPV6_TCLASS_MASK) >> 20; put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); } if (np->rxopt.bits.rxoinfo) { diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 79a196369558..bd91e7ff482b 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1135,7 +1135,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newnp->opt = NULL; newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; - newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); /* @@ -1216,7 +1215,6 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, newnp->opt = NULL; newnp->mcast_oif = inet6_iif(skb); newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; - newnp->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(skb)); newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); /* Clone native IPv6 options from listening socket (if any) @@ -1427,9 +1425,7 @@ ipv6_pktoptions: np->mcast_oif = inet6_iif(opt_skb); if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; - if (np->rxopt.bits.rxtclass) - np->rcv_tclass = ipv6_get_dsfield(ipv6_hdr(opt_skb)); - if (np->rxopt.bits.rxflow) + if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass) np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); if (ipv6_opt_accepted(sk, opt_skb)) { skb_set_owner_r(opt_skb, sk); -- cgit v1.2.3-59-g8ed1b From d8318d7f6bd08eba36ed2a7a23ac5389115958bc Mon Sep 17 00:00:00 2001 From: David Cohen Date: Mon, 9 Dec 2013 15:55:34 -0800 Subject: usb: gadget: move bitflags to the end of usb_gadget struct This patch moves all bitflags to the end of usb_gadget struct in order to improve readability. Signed-off-by: David Cohen Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- include/linux/usb/gadget.h | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 942ef5e053bf..23b3bfd0a842 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -485,6 +485,11 @@ struct usb_gadget_ops { * @max_speed: Maximal speed the UDC can handle. UDC must support this * and all slower speeds. * @state: the state we are now (attached, suspended, configured, etc) + * @name: Identifies the controller hardware type. Used in diagnostics + * and sometimes configuration. + * @dev: Driver model state for this abstract device. + * @out_epnum: last used out ep number + * @in_epnum: last used in ep number * @sg_supported: true if we can handle scatter-gather * @is_otg: True if the USB device port uses a Mini-AB jack, so that the * gadget driver must provide a USB OTG descriptor. @@ -497,11 +502,6 @@ struct usb_gadget_ops { * only supports HNP on a different root port. * @b_hnp_enable: OTG device feature flag, indicating that the A-Host * enabled HNP support. - * @name: Identifies the controller hardware type. Used in diagnostics - * and sometimes configuration. - * @dev: Driver model state for this abstract device. - * @out_epnum: last used out ep number - * @in_epnum: last used in ep number * * Gadgets have a mostly-portable "gadget driver" implementing device * functions, handling all usb configurations and interfaces. Gadget @@ -530,16 +530,17 @@ struct usb_gadget { enum usb_device_speed speed; enum usb_device_speed max_speed; enum usb_device_state state; + const char *name; + struct device dev; + unsigned out_epnum; + unsigned in_epnum; + unsigned sg_supported:1; unsigned is_otg:1; unsigned is_a_peripheral:1; unsigned b_hnp_enable:1; unsigned a_hnp_support:1; unsigned a_alt_hnp_support:1; - const char *name; - struct device dev; - unsigned out_epnum; - unsigned in_epnum; }; #define work_to_gadget(w) (container_of((w), struct usb_gadget, work)) -- cgit v1.2.3-59-g8ed1b From 0b2d2bbade59ab2067f326d6dbc2628bee227fd5 Mon Sep 17 00:00:00 2001 From: David Cohen Date: Mon, 9 Dec 2013 15:55:35 -0800 Subject: usb: gadget: add quirk_ep_out_aligned_size field to struct usb_gadget Due to USB controllers may have different restrictions, usb gadget layer needs to provide a generic way to inform gadget functions to complain with non-standard requirements. This patch adds 'quirk_ep_out_aligned_size' field to struct usb_gadget to inform when controller's epout requires buffer size to be aligned to MaxPacketSize. A helper is also provided to align buffer size when necessary. Cc: Alan Stern Acked-by: Michal Nazarewicz Signed-off-by: David Cohen Signed-off-by: Felipe Balbi --- include/linux/usb/gadget.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'include/linux') diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 23b3bfd0a842..cae8a6216551 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -502,6 +502,8 @@ struct usb_gadget_ops { * only supports HNP on a different root port. * @b_hnp_enable: OTG device feature flag, indicating that the A-Host * enabled HNP support. + * @quirk_ep_out_aligned_size: epout requires buffer size to be aligned to + * MaxPacketSize. * * Gadgets have a mostly-portable "gadget driver" implementing device * functions, handling all usb configurations and interfaces. Gadget @@ -541,6 +543,7 @@ struct usb_gadget { unsigned b_hnp_enable:1; unsigned a_hnp_support:1; unsigned a_alt_hnp_support:1; + unsigned quirk_ep_out_aligned_size:1; }; #define work_to_gadget(w) (container_of((w), struct usb_gadget, work)) @@ -558,6 +561,23 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev) list_for_each_entry(tmp, &(gadget)->ep_list, ep_list) +/** + * usb_ep_align_maybe - returns @len aligned to ep's maxpacketsize if gadget + * requires quirk_ep_out_aligned_size, otherwise reguens len. + * @g: controller to check for quirk + * @ep: the endpoint whose maxpacketsize is used to align @len + * @len: buffer size's length to align to @ep's maxpacketsize + * + * This helper is used in case it's required for any reason to check and maybe + * align buffer's size to an ep's maxpacketsize. + */ +static inline size_t +usb_ep_align_maybe(struct usb_gadget *g, struct usb_ep *ep, size_t len) +{ + return !g->quirk_ep_out_aligned_size ? len : + round_up(len, (size_t)ep->desc->wMaxPacketSize); +} + /** * gadget_is_dualspeed - return true iff the hardware handles high speed * @g: controller that might support both high and full speeds -- cgit v1.2.3-59-g8ed1b From 453c499028bf2ecf3b31ccb7c3657fe1b0b28943 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 14 Nov 2013 11:35:34 +0200 Subject: ASoC: davinci-mcasp: Support for McASP version found in DRA7xx The IP in DRA7xx is similar to the IP found in TI81xxAM3xxx/AM4xxx type of SoCs but it is is integrated with sDMA instead of eDMA. The suitable pcm driver for DRA7xx is the omap-pcm driver which is using dmaengine. In the driver we can configure both dma related structures used for eDMA and sDMA. The only thing we need to make sure that we set the correct dma_data at startup with snd_soc_dai_set_dma_data() Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- .../bindings/sound/davinci-mcasp-audio.txt | 1 + include/linux/platform_data/davinci_asp.h | 1 + sound/soc/davinci/davinci-mcasp.c | 52 +++++++++++++++++++--- 3 files changed, 47 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index 1eed972d4719..990fa71ce804 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt @@ -5,6 +5,7 @@ Required properties: "ti,dm646x-mcasp-audio" : for DM646x platforms "ti,da830-mcasp-audio" : for both DA830 & DA850 platforms "ti,am33xx-mcasp-audio" : for AM33xx platforms (AM33xx, AM43xx, TI81xx) + "ti,dra7-mcasp-audio" : for DRA7xx platforms - reg : Should contain reg specifiers for the entries in the reg-names property. - reg-names : Should contain: diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h index 689a856b86f9..5245992b0367 100644 --- a/include/linux/platform_data/davinci_asp.h +++ b/include/linux/platform_data/davinci_asp.h @@ -92,6 +92,7 @@ enum { MCASP_VERSION_1 = 0, /* DM646x */ MCASP_VERSION_2, /* DA8xx/OMAPL1x */ MCASP_VERSION_3, /* TI81xx/AM33xx */ + MCASP_VERSION_4, /* DRA7xxx */ }; enum mcbsp_clk_input_pin { diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 93f2e294d649..fc8c13d2f31e 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -31,12 +31,14 @@ #include #include #include +#include #include "davinci-pcm.h" #include "davinci-mcasp.h" struct davinci_mcasp { struct davinci_pcm_dma_params dma_params[2]; + struct snd_dmaengine_dai_dma_data dma_data[2]; void __iomem *base; u32 fifo_base; struct device *dev; @@ -458,7 +460,9 @@ static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream, u8 max_active_serializers = (channels + slots - 1) / slots; u32 reg; /* Default configuration */ - mcasp_set_bits(mcasp->base + DAVINCI_MCASP_PWREMUMGT_REG, MCASP_SOFT); + if (mcasp->version != MCASP_VERSION_4) + mcasp_set_bits(mcasp->base + DAVINCI_MCASP_PWREMUMGT_REG, + MCASP_SOFT); /* All PINS as McASP */ mcasp_set_reg(mcasp->base + DAVINCI_MCASP_PFUNC_REG, 0x00000000); @@ -605,6 +609,8 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); struct davinci_pcm_dma_params *dma_params = &mcasp->dma_params[substream->stream]; + struct snd_dmaengine_dai_dma_data *dma_data = + &mcasp->dma_data[substream->stream]; int word_length; u8 fifo_level; u8 slots = mcasp->tdm_slots; @@ -666,6 +672,8 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, dma_params->acnt = dma_params->data_type; dma_params->fifo_level = fifo_level; + dma_data->maxburst = fifo_level; + davinci_config_channel_size(mcasp, word_length); return 0; @@ -711,7 +719,12 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); - snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params); + if (mcasp->version == MCASP_VERSION_4) + snd_soc_dai_set_dma_data(dai, substream, + &mcasp->dma_data[substream->stream]); + else + snd_soc_dai_set_dma_data(dai, substream, mcasp->dma_params); + return 0; } @@ -794,6 +807,13 @@ static struct snd_platform_data omap2_mcasp_pdata = { .version = MCASP_VERSION_3, }; +static struct snd_platform_data dra7_mcasp_pdata = { + .tx_dma_offset = 0x200, + .rx_dma_offset = 0x284, + .asp_chan_q = EVENTQ_0, + .version = MCASP_VERSION_4, +}; + static const struct of_device_id mcasp_dt_ids[] = { { .compatible = "ti,dm646x-mcasp-audio", @@ -807,6 +827,10 @@ static const struct of_device_id mcasp_dt_ids[] = { .compatible = "ti,am33xx-mcasp-audio", .data = &omap2_mcasp_pdata, }, + { + .compatible = "ti,dra7-mcasp-audio", + .data = &dra7_mcasp_pdata, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mcasp_dt_ids); @@ -999,6 +1023,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) else dma_data->dma_addr = mem->start + pdata->tx_dma_offset; + /* Unconditional dmaengine stuff */ + mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_data->dma_addr; + res = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (res) dma_data->channel = res->start; @@ -1015,6 +1042,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) else dma_data->dma_addr = mem->start + pdata->rx_dma_offset; + /* Unconditional dmaengine stuff */ + mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_data->dma_addr; + if (mcasp->version < MCASP_VERSION_3) { mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE; /* dma_data->dma_addr is pointing to the data port address */ @@ -1029,6 +1059,10 @@ static int davinci_mcasp_probe(struct platform_device *pdev) else dma_data->channel = pdata->rx_dma_channel; + /* Unconditional dmaengine stuff */ + mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx"; + mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].filter_data = "rx"; + dev_set_drvdata(&pdev->dev, mcasp); ret = snd_soc_register_component(&pdev->dev, &davinci_mcasp_component, &davinci_mcasp_dai[pdata->op_mode], 1); @@ -1036,10 +1070,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev) if (ret != 0) goto err_release_clk; - ret = davinci_soc_platform_register(&pdev->dev); - if (ret) { - dev_err(&pdev->dev, "register PCM failed: %d\n", ret); - goto err_unregister_component; + if (mcasp->version != MCASP_VERSION_4) { + ret = davinci_soc_platform_register(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "register PCM failed: %d\n", ret); + goto err_unregister_component; + } } return 0; @@ -1054,9 +1090,11 @@ err_release_clk: static int davinci_mcasp_remove(struct platform_device *pdev) { + struct davinci_mcasp *mcasp = dev_get_drvdata(&pdev->dev); snd_soc_unregister_component(&pdev->dev); - davinci_soc_platform_unregister(&pdev->dev); + if (mcasp->version != MCASP_VERSION_4) + davinci_soc_platform_unregister(&pdev->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); -- cgit v1.2.3-59-g8ed1b From 0ad7c00057dc1640647c1dc81ccbd009de17a767 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 26 Nov 2013 10:04:22 -0700 Subject: dma: add channel request API that supports deferred probe dma_request_slave_channel() simply returns NULL whenever DMA channel lookup fails. Lookup could fail for two distinct reasons: a) No DMA specification exists for the channel name. This includes situations where no DMA specifications exist at all, or other general lookup problems. b) A DMA specification does exist, yet the driver for that channel is not yet registered. Case (b) should trigger deferred probe in client drivers. However, since they have no way to differentiate the two situations, it cannot. Implement new function dma_request_slave_channel_reason(), which performs identically to dma_request_slave_channel(), except that it returns an error-pointer rather than NULL, which allows callers to detect when deferred probe should occur. Eventually, all drivers should be converted to this new API, the old API removed, and the new API renamed to the more desirable name. This patch doesn't convert the existing API and all drivers in one go, since some drivers call dma_request_slave_channel() then dma_request_channel() if that fails. That would require either modifying dma_request_channel() in the same way, or adding extra error-handling code to all affected drivers, and there are close to 100 drivers using the other API, rather than just the 15-20 or so that use dma_request_slave_channel(), which might be tenable in a single patch. acpi_dma_request_slave_chan_by_name() doesn't currently implement deferred probe. It should, but this will be addressed later. Acked-by: Dan Williams Signed-off-by: Stephen Warren Signed-off-by: Vinod Koul --- drivers/dma/dmaengine.c | 35 +++++++++++++++++++++++++++++++---- drivers/dma/of-dma.c | 15 +++++++++------ include/linux/dmaengine.h | 8 ++++++++ 3 files changed, 48 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index ea806bdc12ef..e17e9b22d85e 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -540,6 +540,8 @@ EXPORT_SYMBOL_GPL(dma_get_slave_channel); * @mask: capabilities that the channel must satisfy * @fn: optional callback to disposition available channels * @fn_param: opaque parameter to pass to dma_filter_fn + * + * Returns pointer to appropriate DMA channel on success or NULL. */ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param) @@ -591,18 +593,43 @@ EXPORT_SYMBOL_GPL(__dma_request_channel); * dma_request_slave_channel - try to allocate an exclusive slave channel * @dev: pointer to client device structure * @name: slave channel name + * + * Returns pointer to appropriate DMA channel on success or an error pointer. */ -struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name) +struct dma_chan *dma_request_slave_channel_reason(struct device *dev, + const char *name) { + struct dma_chan *chan; + /* If device-tree is present get slave info from here */ if (dev->of_node) return of_dma_request_slave_channel(dev->of_node, name); /* If device was enumerated by ACPI get slave info from here */ - if (ACPI_HANDLE(dev)) - return acpi_dma_request_slave_chan_by_name(dev, name); + if (ACPI_HANDLE(dev)) { + chan = acpi_dma_request_slave_chan_by_name(dev, name); + if (chan) + return chan; + } - return NULL; + return ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL_GPL(dma_request_slave_channel_reason); + +/** + * dma_request_slave_channel - try to allocate an exclusive slave channel + * @dev: pointer to client device structure + * @name: slave channel name + * + * Returns pointer to appropriate DMA channel on success or NULL. + */ +struct dma_chan *dma_request_slave_channel(struct device *dev, + const char *name) +{ + struct dma_chan *ch = dma_request_slave_channel_reason(dev, name); + if (IS_ERR(ch)) + return NULL; + return ch; } EXPORT_SYMBOL_GPL(dma_request_slave_channel); diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c index 0b88dd3d05f4..e8fe9dc455f4 100644 --- a/drivers/dma/of-dma.c +++ b/drivers/dma/of-dma.c @@ -143,7 +143,7 @@ static int of_dma_match_channel(struct device_node *np, const char *name, * @np: device node to get DMA request from * @name: name of desired channel * - * Returns pointer to appropriate dma channel on success or NULL on error. + * Returns pointer to appropriate DMA channel on success or an error pointer. */ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, const char *name) @@ -152,17 +152,18 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, struct of_dma *ofdma; struct dma_chan *chan; int count, i; + int ret_no_channel = -ENODEV; if (!np || !name) { pr_err("%s: not enough information provided\n", __func__); - return NULL; + return ERR_PTR(-ENODEV); } count = of_property_count_strings(np, "dma-names"); if (count < 0) { pr_err("%s: dma-names property of node '%s' missing or empty\n", __func__, np->full_name); - return NULL; + return ERR_PTR(-ENODEV); } for (i = 0; i < count; i++) { @@ -172,10 +173,12 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, mutex_lock(&of_dma_lock); ofdma = of_dma_find_controller(&dma_spec); - if (ofdma) + if (ofdma) { chan = ofdma->of_dma_xlate(&dma_spec, ofdma); - else + } else { + ret_no_channel = -EPROBE_DEFER; chan = NULL; + } mutex_unlock(&of_dma_lock); @@ -185,7 +188,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, return chan; } - return NULL; + return ERR_PTR(ret_no_channel); } /** diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 41cf0c399288..ed92b30a02fd 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -22,6 +22,7 @@ #define LINUX_DMAENGINE_H #include +#include #include #include #include @@ -1040,6 +1041,8 @@ enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx); void dma_issue_pending_all(void); struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param); +struct dma_chan *dma_request_slave_channel_reason(struct device *dev, + const char *name); struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name); void dma_release_channel(struct dma_chan *chan); #else @@ -1063,6 +1066,11 @@ static inline struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, { return NULL; } +static inline struct dma_chan *dma_request_slave_channel_reason( + struct device *dev, const char *name) +{ + return ERR_PTR(-ENODEV); +} static inline struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name) { -- cgit v1.2.3-59-g8ed1b From 8010dad55a0ab0e829f3733854e5235eef4e2734 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 26 Nov 2013 12:40:51 -0700 Subject: dma: add dma_get_any_slave_channel(), for use in of_xlate() mmp_pdma.c implements a custom of_xlate() function that is 95% identical to what Tegra will need. Create a function to implement the common part, so everyone doesn't just cut/paste the implementation. Cc: Dan Williams Cc: Vinod Koul Cc: Lars-Peter Clausen Cc: dmaengine@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Stephen Warren Signed-off-by: Vinod Koul --- drivers/dma/dmaengine.c | 28 ++++++++++++++++++++++++++++ drivers/dma/mmp_pdma.c | 30 +++++++----------------------- include/linux/dmaengine.h | 1 + 3 files changed, 36 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index ea806bdc12ef..4f08ee8c17b4 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -535,6 +535,34 @@ struct dma_chan *dma_get_slave_channel(struct dma_chan *chan) } EXPORT_SYMBOL_GPL(dma_get_slave_channel); +struct dma_chan *dma_get_any_slave_channel(struct dma_device *device) +{ + dma_cap_mask_t mask; + struct dma_chan *chan; + int err; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* lock against __dma_request_channel */ + mutex_lock(&dma_list_mutex); + + chan = private_candidate(&mask, device, NULL, NULL); + if (chan) { + err = dma_chan_get(chan); + if (err) { + pr_debug("%s: failed to get %s: (%d)\n", + __func__, dma_chan_name(chan), err); + chan = NULL; + } + } + + mutex_unlock(&dma_list_mutex); + + return chan; +} +EXPORT_SYMBOL_GPL(dma_get_any_slave_channel); + /** * __dma_request_channel - try to allocate an exclusive channel * @mask: capabilities that the channel must satisfy diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index dcb1e05149a7..2998f1bffac1 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -893,33 +893,17 @@ static struct dma_chan *mmp_pdma_dma_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma) { struct mmp_pdma_device *d = ofdma->of_dma_data; - struct dma_chan *chan, *candidate; + struct dma_chan *chan; + struct mmp_pdma_chan *c; -retry: - candidate = NULL; - - /* walk the list of channels registered with the current instance and - * find one that is currently unused */ - list_for_each_entry(chan, &d->device.channels, device_node) - if (chan->client_count == 0) { - candidate = chan; - break; - } - - if (!candidate) + chan = dma_get_any_slave_channel(&d->device); + if (!chan) return NULL; - /* dma_get_slave_channel will return NULL if we lost a race between - * the lookup and the reservation */ - chan = dma_get_slave_channel(candidate); - - if (chan) { - struct mmp_pdma_chan *c = to_mmp_pdma_chan(chan); - c->drcmr = dma_spec->args[0]; - return chan; - } + c = to_mmp_pdma_chan(chan); + c->drcmr = dma_spec->args[0]; - goto retry; + return chan; } static int mmp_pdma_probe(struct platform_device *op) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 41cf0c399288..09ef23ee8bce 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -1079,6 +1079,7 @@ int dma_async_device_register(struct dma_device *device); void dma_async_device_unregister(struct dma_device *device); void dma_run_dependencies(struct dma_async_tx_descriptor *tx); struct dma_chan *dma_get_slave_channel(struct dma_chan *chan); +struct dma_chan *dma_get_any_slave_channel(struct dma_device *device); struct dma_chan *net_dma_find_channel(void); #define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y) #define dma_request_slave_channel_compat(mask, x, y, dev, name) \ -- cgit v1.2.3-59-g8ed1b From 48fc7dbd52c0559647291f33a10ccdc6cdbe4c72 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 5 Dec 2013 17:07:27 -0800 Subject: usb: xhci: change enumeration scheme to 'new scheme' by default Change the default enumeration scheme for xhci attached non-SuperSpeed devices from: Reset SetAddress [xhci address-device BSR = 0] GetDescriptor(8) GetDescriptor(18) ...to: Reset [xhci address-device BSR = 1] GetDescriptor(64) Reset SetAddress [xhci address-device BSR = 0] GetDescriptor(18) ...as some devices misbehave when encountering a SetAddress command prior to GetDescriptor. There are known legacy devices that require this scheme, but testing has found at least one USB3 device that fails enumeration when presented with this ordering. For now, follow the ehci case and enable 'new scheme' by default for non-SuperSpeed devices. To support this enumeration scheme on xhci the AddressDevice operation needs to be performed twice. The first instance of the command enables the HC's device and slot context info for the device, but omits sending the device a SetAddress command (BSR == block set address request). Then, after GetDescriptor completes, follow up with the full AddressDevice+SetAddress operation. As mentioned before, this ordering of events with USB3 devices causes an extra state transition to be exposed to xhci. Previously USB3 devices would transition directly from 'enabled' to 'addressed' and never need to underrun responses to 'get descriptor'. We do see the 64-byte descriptor fetch the correct data, but the following 18-byte descriptor read after the reset gets: bLength = 0 bDescriptorType = 0 bcdUSB = 0 bDeviceClass = 0 bDeviceSubClass = 0 bDeviceProtocol = 0 bMaxPacketSize0 = 9 instead of: bLength = 12 bDescriptorType = 1 bcdUSB = 300 bDeviceClass = 0 bDeviceSubClass = 0 bDeviceProtocol = 0 bMaxPacketSize0 = 9 which results in the discovery process looping until falling back to 'old scheme' enumeration. Acked-by: Alan Stern Reported-by: David Moore Suggested-by: Sarah Sharp Reported-by: Dan Carpenter Signed-off-by: Dan Williams Signed-off-by: Sarah Sharp --- drivers/usb/core/hub.c | 46 +++++++++++++++++++++++++++++++++++++++++--- drivers/usb/host/xhci-pci.c | 1 + drivers/usb/host/xhci-plat.c | 1 + drivers/usb/host/xhci-ring.c | 6 +++--- drivers/usb/host/xhci.c | 19 ++++++++++++++---- drivers/usb/host/xhci.h | 11 ++++++++++- include/linux/usb/hcd.h | 2 ++ 7 files changed, 75 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 32e1035d4f59..6a11eff74d3c 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2498,6 +2498,21 @@ static unsigned hub_is_wusb(struct usb_hub *hub) #define HUB_LONG_RESET_TIME 200 #define HUB_RESET_TIMEOUT 800 +/* + * "New scheme" enumeration causes an extra state transition to be + * exposed to an xhci host and causes USB3 devices to receive control + * commands in the default state. This has been seen to cause + * enumeration failures, so disable this enumeration scheme for USB3 + * devices. + */ +static bool use_new_scheme(struct usb_device *udev, int retry) +{ + if (udev->speed == USB_SPEED_SUPER) + return false; + + return USE_NEW_SCHEME(retry); +} + static int hub_port_reset(struct usb_hub *hub, int port1, struct usb_device *udev, unsigned int delay, bool warm); @@ -3956,6 +3971,20 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev) } } +static int hub_enable_device(struct usb_device *udev) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (!hcd->driver->enable_device) + return 0; + if (udev->state == USB_STATE_ADDRESS) + return 0; + if (udev->state != USB_STATE_DEFAULT) + return -EINVAL; + + return hcd->driver->enable_device(hcd, udev); +} + /* Reset device, (re)assign address, get device descriptor. * Device connection must be stable, no more debouncing needed. * Returns device in USB_STATE_ADDRESS, except on error. @@ -4068,7 +4097,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, * this area, and this is how Linux has done it for ages. * Change it cautiously. * - * NOTE: If USE_NEW_SCHEME() is true we will start by issuing + * NOTE: If use_new_scheme() is true we will start by issuing * a 64-byte GET_DESCRIPTOR request. This is what Windows does, * so it may help with some non-standards-compliant devices. * Otherwise we start with SET_ADDRESS and then try to read the @@ -4076,10 +4105,17 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, * value. */ for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) { - if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) { + bool did_new_scheme = false; + + if (use_new_scheme(udev, retry_counter)) { struct usb_device_descriptor *buf; int r = 0; + did_new_scheme = true; + retval = hub_enable_device(udev); + if (retval < 0) + goto fail; + #define GET_DESCRIPTOR_BUFSIZE 64 buf = kmalloc(GET_DESCRIPTOR_BUFSIZE, GFP_NOIO); if (!buf) { @@ -4168,7 +4204,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, * - read ep0 maxpacket even for high and low speed, */ msleep(10); - if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) + /* use_new_scheme() checks the speed which may have + * changed since the initial look so we cache the result + * in did_new_scheme + */ + if (did_new_scheme) break; } diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index b8dffd59eb25..4221dee924b5 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -331,6 +331,7 @@ static const struct hc_driver xhci_pci_hc_driver = { .check_bandwidth = xhci_check_bandwidth, .reset_bandwidth = xhci_reset_bandwidth, .address_device = xhci_address_device, + .enable_device = xhci_enable_device, .update_hub_device = xhci_update_hub_device, .reset_device = xhci_discover_or_reset_device, diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 9d29aa1b1bc8..8abda5c73ca1 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -69,6 +69,7 @@ static const struct hc_driver xhci_plat_xhci_driver = { .check_bandwidth = xhci_check_bandwidth, .reset_bandwidth = xhci_reset_bandwidth, .address_device = xhci_address_device, + .enable_device = xhci_enable_device, .update_hub_device = xhci_update_hub_device, .reset_device = xhci_discover_or_reset_device, diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index fe9208a5d103..d26cd9474aa6 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -4004,12 +4004,12 @@ int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id) /* Queue an address device command TRB */ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id) + u32 slot_id, enum xhci_setup_dev setup) { return queue_command(xhci, lower_32_bits(in_ctx_ptr), upper_32_bits(in_ctx_ptr), 0, - TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id), - false); + TRB_TYPE(TRB_ADDR_DEV) | SLOT_ID_FOR_TRB(slot_id) + | (setup == SETUP_CONTEXT_ONLY ? TRB_BSR : 0), false); } int xhci_queue_vendor_command(struct xhci_hcd *xhci, diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 7fe6f664054f..6598f7ee7938 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3709,12 +3709,13 @@ disable_slot: } /* - * Issue an Address Device command (which will issue a SetAddress request to - * the device). + * Issue an Address Device command and optionally send a corresponding + * SetAddress request to the device. * We should be protected by the usb_address0_mutex in khubd's hub_port_init, so * we should only issue and wait on one address command at the same time. */ -int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) +static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, + enum xhci_setup_dev setup) { unsigned long flags; int timeleft; @@ -3773,7 +3774,7 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) spin_lock_irqsave(&xhci->lock, flags); cmd_trb = xhci_find_next_enqueue(xhci->cmd_ring); ret = xhci_queue_address_device(xhci, virt_dev->in_ctx->dma, - udev->slot_id); + udev->slot_id, setup); if (ret) { spin_unlock_irqrestore(&xhci->lock, flags); xhci_dbg_trace(xhci, trace_xhci_dbg_address, @@ -3868,6 +3869,16 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) return 0; } +int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev) +{ + return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ADDRESS); +} + +int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev) +{ + return xhci_setup_device(hcd, udev, SETUP_CONTEXT_ONLY); +} + /* * Transfer the port index into real index in the HW port status * registers. Caculate offset between the port's PORTSC register diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 7807f621a713..24344aab2107 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1108,6 +1108,14 @@ struct xhci_event_cmd { }; /* flags bitmasks */ + +/* Address device - disable SetAddress */ +#define TRB_BSR (1<<9) +enum xhci_setup_dev { + SETUP_CONTEXT_ONLY, + SETUP_CONTEXT_ADDRESS, +}; + /* bits 16:23 are the virtual function ID */ /* bits 24:31 are the slot ID */ #define TRB_TO_SLOT_ID(p) (((p) & (0xff<<24)) >> 24) @@ -1760,6 +1768,7 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint **eps, unsigned int num_eps, gfp_t mem_flags); int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev); +int xhci_enable_device(struct usb_hcd *hcd, struct usb_device *udev); int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev); int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, struct usb_device *udev, int enable); @@ -1783,7 +1792,7 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code); void xhci_ring_cmd_db(struct xhci_hcd *xhci); int xhci_queue_slot_control(struct xhci_hcd *xhci, u32 trb_type, u32 slot_id); int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id); + u32 slot_id, enum xhci_setup_dev); int xhci_queue_vendor_command(struct xhci_hcd *xhci, u32 field1, u32 field2, u32 field3, u32 field4); int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id, diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 758ce80d085f..efe8d8a7c7ad 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -353,6 +353,8 @@ struct hc_driver { void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *); /* Returns the hardware-chosen device address */ int (*address_device)(struct usb_hcd *, struct usb_device *udev); + /* prepares the hardware to send commands to the device */ + int (*enable_device)(struct usb_hcd *, struct usb_device *udev); /* Notifies the HCD after a hub descriptor is fetched. * Will block. */ -- cgit v1.2.3-59-g8ed1b From 28303ca3090c0aa0dbbb72714c51fceb4b939f6d Mon Sep 17 00:00:00 2001 From: Weng Meiling Date: Sat, 30 Nov 2013 17:56:44 +0800 Subject: sunrpc: fix some typos Signed-off-by: Weng Meiling Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/svc.h | 2 +- net/sunrpc/xprtsock.c | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h index 6eecfc2e4f98..b631642318c5 100644 --- a/include/linux/sunrpc/svc.h +++ b/include/linux/sunrpc/svc.h @@ -368,7 +368,7 @@ struct svc_program { struct svc_program * pg_next; /* other programs (same xprt) */ u32 pg_prog; /* program number */ unsigned int pg_lovers; /* lowest version */ - unsigned int pg_hivers; /* lowest version */ + unsigned int pg_hivers; /* highest version */ unsigned int pg_nvers; /* number of versions */ struct svc_version ** pg_vers; /* version array */ char * pg_name; /* service name */ diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index dd9d295813cf..0f4f39174a70 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2932,10 +2932,9 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) /* * Once we've associated a backchannel xprt with a connection, - * we want to keep it around as long as long as the connection - * lasts, in case we need to start using it for a backchannel - * again; this reference won't be dropped until bc_xprt is - * destroyed. + * we want to keep it around as long as the connection lasts, + * in case we need to start using it for a backchannel again; + * this reference won't be dropped until bc_xprt is destroyed. */ xprt_get(xprt); args->bc_xprt->xpt_bc_xprt = xprt; -- cgit v1.2.3-59-g8ed1b From ad6c81359fc3e6086d1d6f91acda9d5d0e64b2c3 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Sun, 8 Dec 2013 12:16:10 +0100 Subject: ipv4: add support for IFA_FLAGS nl attribute Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/inetdevice.h | 2 +- net/ipv4/devinet.c | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index ae174ca565c9..562e5c7c5d35 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -136,8 +136,8 @@ struct in_ifaddr { __be32 ifa_mask; __be32 ifa_broadcast; unsigned char ifa_scope; - unsigned char ifa_flags; unsigned char ifa_prefixlen; + __u32 ifa_flags; char ifa_label[IFNAMSIZ]; /* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */ diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 43065be36301..6f49efc9d4b7 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -99,6 +99,7 @@ static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = { [IFA_BROADCAST] = { .type = NLA_U32 }, [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, + [IFA_FLAGS] = { .type = NLA_U32 }, }; #define IN4_ADDR_HSIZE_SHIFT 8 @@ -757,7 +758,8 @@ static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, INIT_HLIST_NODE(&ifa->hash); ifa->ifa_prefixlen = ifm->ifa_prefixlen; ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); - ifa->ifa_flags = ifm->ifa_flags; + ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : + ifm->ifa_flags; ifa->ifa_scope = ifm->ifa_scope; ifa->ifa_dev = in_dev; @@ -1437,7 +1439,8 @@ static size_t inet_nlmsg_size(void) + nla_total_size(4) /* IFA_ADDRESS */ + nla_total_size(4) /* IFA_LOCAL */ + nla_total_size(4) /* IFA_BROADCAST */ - + nla_total_size(IFNAMSIZ); /* IFA_LABEL */ + + nla_total_size(IFNAMSIZ) /* IFA_LABEL */ + + nla_total_size(4); /* IFA_FLAGS */ } static inline u32 cstamp_delta(unsigned long cstamp) @@ -1505,6 +1508,7 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, nla_put_be32(skb, IFA_BROADCAST, ifa->ifa_broadcast)) || (ifa->ifa_label[0] && nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) || + nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) || put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp, preferred, valid)) goto nla_put_failure; -- cgit v1.2.3-59-g8ed1b From 37cb0620073cb64101d9307931c135c70b2e3f04 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Tue, 10 Dec 2013 20:45:41 -0800 Subject: tipc: remove TIPC usage of field af_packet_priv in struct net_device TIPC is currently using the field 'af_packet_priv' in struct net_device as a handle to find the bearer instance associated to the given network device. But, by doing so it is blocking other networking cleanups, such as the one discussed here: http://patchwork.ozlabs.org/patch/178044/ This commit removes this usage from TIPC. Instead, we introduce a new field, 'tipc_ptr', to the net_device structure, to serve this purpose. When TIPC bearer is enabled, the bearer object is associated to 'tipc_ptr'. When a TIPC packet arrives in the recv_msg() upcall from a networking device, the bearer object can now be obtained from 'tipc_ptr'. When a bearer is disabled, the bearer object is detached from its underlying network device by setting 'tipc_ptr' to NULL. Additionally, an RCU lock is used to protect the new pointer. Henceforth, the existing tipc_net_lock is used in write mode to serialize write accesses to this pointer, while the new RCU lock is applied on the read side to ensure that the pointer is 100% valid within its wrapped area for all readers. Signed-off-by: Ying Xue Cc: Patrick McHardy Reviewed-by: Paul Gortmaker Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- include/linux/netdevice.h | 3 +++ net/tipc/bearer.h | 2 ++ net/tipc/eth_media.c | 55 +++++++++++++++++++++++++++-------------------- net/tipc/ib_media.c | 54 ++++++++++++++++++++++++++-------------------- 4 files changed, 68 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 9d55e5188b96..0ca8100f9fbc 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1282,6 +1282,9 @@ struct net_device { #endif #if IS_ENABLED(CONFIG_NET_DSA) struct dsa_switch_tree *dsa_ptr; /* dsa specific data */ +#endif +#if IS_ENABLED(CONFIG_TIPC) + struct tipc_bearer __rcu *tipc_ptr; /* TIPC specific data */ #endif void *atalk_ptr; /* AppleTalk link */ struct in_device __rcu *ip_ptr; /* IPv4 specific data */ diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index e50266aa4d10..91b8d8b92373 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -105,6 +105,7 @@ struct tipc_media { /** * struct tipc_bearer - Generic TIPC bearer structure + * @dev: ptr to associated network device * @usr_handle: pointer to additional media-specific information about bearer * @mtu: max packet size bearer can support * @lock: spinlock for controlling access to bearer @@ -127,6 +128,7 @@ struct tipc_media { * care of initializing all other fields. */ struct tipc_bearer { + struct net_device *dev; void *usr_handle; /* initalized by media */ u32 mtu; /* initalized by media */ struct tipc_media_addr addr; /* initalized by media */ diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 37fb145476ec..c5f685dee15b 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -63,6 +63,9 @@ static int eth_started; static int recv_notification(struct notifier_block *nb, unsigned long evt, void *dv); +static int recv_msg(struct sk_buff *buf, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev); + /* * Network device notifier info */ @@ -71,6 +74,11 @@ static struct notifier_block notifier = { .priority = 0 }; +static struct packet_type tipc_packet_type __read_mostly = { + .type = __constant_htons(ETH_P_TIPC), + .func = recv_msg, +}; + /** * eth_media_addr_set - initialize Ethernet media address structure * @@ -128,20 +136,25 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, static int recv_msg(struct sk_buff *buf, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - struct eth_media *eb_ptr = (struct eth_media *)pt->af_packet_priv; + struct tipc_bearer *b_ptr; if (!net_eq(dev_net(dev), &init_net)) { kfree_skb(buf); return NET_RX_DROP; } - if (likely(eb_ptr->bearer)) { + rcu_read_lock(); + b_ptr = rcu_dereference(dev->tipc_ptr); + if (likely(b_ptr)) { if (likely(buf->pkt_type <= PACKET_BROADCAST)) { buf->next = NULL; - tipc_recv_msg(buf, eb_ptr->bearer); + tipc_recv_msg(buf, b_ptr); + rcu_read_unlock(); return NET_RX_SUCCESS; } } + rcu_read_unlock(); + kfree_skb(buf); return NET_RX_DROP; } @@ -151,10 +164,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, */ static void setup_media(struct work_struct *work) { - struct eth_media *eb_ptr = - container_of(work, struct eth_media, setup); - - dev_add_pack(&eb_ptr->tipc_packet_type); + dev_add_pack(&tipc_packet_type); } /** @@ -183,15 +193,11 @@ static int enable_media(struct tipc_bearer *tb_ptr) /* Create Ethernet bearer for device */ eb_ptr->dev = dev; - eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); - eb_ptr->tipc_packet_type.dev = dev; - eb_ptr->tipc_packet_type.func = recv_msg; - eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr; - INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list)); INIT_WORK(&eb_ptr->setup, setup_media); schedule_work(&eb_ptr->setup); /* Associate TIPC bearer with Ethernet bearer */ + tb_ptr->dev = dev; eb_ptr->bearer = tb_ptr; tb_ptr->usr_handle = (void *)eb_ptr; memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); @@ -200,6 +206,7 @@ static int enable_media(struct tipc_bearer *tb_ptr) tb_ptr->bcast_addr.broadcast = 1; tb_ptr->mtu = dev->mtu; eth_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); + rcu_assign_pointer(dev->tipc_ptr, tb_ptr); return 0; } @@ -213,7 +220,7 @@ static void cleanup_media(struct work_struct *work) struct eth_media *eb_ptr = container_of(work, struct eth_media, cleanup); - dev_remove_pack(&eb_ptr->tipc_packet_type); + dev_remove_pack(&tipc_packet_type); dev_put(eb_ptr->dev); eb_ptr->dev = NULL; } @@ -232,6 +239,7 @@ static void disable_media(struct tipc_bearer *tb_ptr) eb_ptr->bearer = NULL; INIT_WORK(&eb_ptr->cleanup, cleanup_media); schedule_work(&eb_ptr->cleanup); + RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL); } /** @@ -243,21 +251,20 @@ static void disable_media(struct tipc_bearer *tb_ptr) static int recv_notification(struct notifier_block *nb, unsigned long evt, void *ptr) { + struct tipc_bearer *b_ptr; struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct eth_media *eb_ptr = ð_media_array[0]; - struct eth_media *stop = ð_media_array[MAX_ETH_MEDIA]; if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; - while ((eb_ptr->dev != dev)) { - if (++eb_ptr == stop) - return NOTIFY_DONE; /* couldn't find device */ - } - if (!eb_ptr->bearer) + rcu_read_lock(); + b_ptr = rcu_dereference(dev->tipc_ptr); + if (!b_ptr) { + rcu_read_unlock(); return NOTIFY_DONE; /* bearer had been disabled */ + } - eb_ptr->bearer->mtu = dev->mtu; + b_ptr->mtu = dev->mtu; switch (evt) { case NETDEV_CHANGE: @@ -266,13 +273,15 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, case NETDEV_DOWN: case NETDEV_CHANGEMTU: case NETDEV_CHANGEADDR: - tipc_reset_bearer(eb_ptr->bearer); + tipc_reset_bearer(b_ptr); break; case NETDEV_UNREGISTER: case NETDEV_CHANGENAME: - tipc_disable_bearer(eb_ptr->bearer->name); + tipc_disable_bearer(b_ptr->name); break; } + rcu_read_unlock(); + return NOTIFY_OK; } diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c index 48e1c07842e6..9fdf03cd672b 100644 --- a/net/tipc/ib_media.c +++ b/net/tipc/ib_media.c @@ -62,6 +62,13 @@ struct ib_media { static struct ib_media ib_media_array[MAX_IB_MEDIA]; static int ib_started; +static int recv_msg(struct sk_buff *buf, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev); + +static struct packet_type tipc_packet_type __read_mostly = { + .type = __constant_htons(ETH_P_TIPC), + .func = recv_msg, +}; /** * ib_media_addr_set - initialize Infiniband media address structure @@ -120,20 +127,25 @@ static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr, static int recv_msg(struct sk_buff *buf, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { - struct ib_media *ib_ptr = (struct ib_media *)pt->af_packet_priv; + struct tipc_bearer *b_ptr; if (!net_eq(dev_net(dev), &init_net)) { kfree_skb(buf); return NET_RX_DROP; } - if (likely(ib_ptr->bearer)) { + rcu_read_lock(); + b_ptr = rcu_dereference(dev->tipc_ptr); + if (likely(b_ptr)) { if (likely(buf->pkt_type <= PACKET_BROADCAST)) { buf->next = NULL; - tipc_recv_msg(buf, ib_ptr->bearer); + tipc_recv_msg(buf, b_ptr); + rcu_read_unlock(); return NET_RX_SUCCESS; } } + rcu_read_unlock(); + kfree_skb(buf); return NET_RX_DROP; } @@ -143,10 +155,7 @@ static int recv_msg(struct sk_buff *buf, struct net_device *dev, */ static void setup_media(struct work_struct *work) { - struct ib_media *ib_ptr = - container_of(work, struct ib_media, setup); - - dev_add_pack(&ib_ptr->tipc_packet_type); + dev_add_pack(&tipc_packet_type); } /** @@ -175,15 +184,11 @@ static int enable_media(struct tipc_bearer *tb_ptr) /* Create InfiniBand bearer for device */ ib_ptr->dev = dev; - ib_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); - ib_ptr->tipc_packet_type.dev = dev; - ib_ptr->tipc_packet_type.func = recv_msg; - ib_ptr->tipc_packet_type.af_packet_priv = ib_ptr; - INIT_LIST_HEAD(&(ib_ptr->tipc_packet_type.list)); INIT_WORK(&ib_ptr->setup, setup_media); schedule_work(&ib_ptr->setup); /* Associate TIPC bearer with InfiniBand bearer */ + tb_ptr->dev = dev; ib_ptr->bearer = tb_ptr; tb_ptr->usr_handle = (void *)ib_ptr; memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value)); @@ -192,6 +197,7 @@ static int enable_media(struct tipc_bearer *tb_ptr) tb_ptr->bcast_addr.broadcast = 1; tb_ptr->mtu = dev->mtu; ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr); + rcu_assign_pointer(dev->tipc_ptr, tb_ptr); return 0; } @@ -205,7 +211,7 @@ static void cleanup_bearer(struct work_struct *work) struct ib_media *ib_ptr = container_of(work, struct ib_media, cleanup); - dev_remove_pack(&ib_ptr->tipc_packet_type); + dev_remove_pack(&tipc_packet_type); dev_put(ib_ptr->dev); ib_ptr->dev = NULL; } @@ -224,6 +230,7 @@ static void disable_media(struct tipc_bearer *tb_ptr) ib_ptr->bearer = NULL; INIT_WORK(&ib_ptr->cleanup, cleanup_bearer); schedule_work(&ib_ptr->cleanup); + RCU_INIT_POINTER(tb_ptr->dev->tipc_ptr, NULL); } /** @@ -235,21 +242,20 @@ static void disable_media(struct tipc_bearer *tb_ptr) static int recv_notification(struct notifier_block *nb, unsigned long evt, void *ptr) { + struct tipc_bearer *b_ptr; struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct ib_media *ib_ptr = &ib_media_array[0]; - struct ib_media *stop = &ib_media_array[MAX_IB_MEDIA]; if (!net_eq(dev_net(dev), &init_net)) return NOTIFY_DONE; - while ((ib_ptr->dev != dev)) { - if (++ib_ptr == stop) - return NOTIFY_DONE; /* couldn't find device */ - } - if (!ib_ptr->bearer) + rcu_read_lock(); + b_ptr = rcu_dereference(dev->tipc_ptr); + if (!b_ptr) { + rcu_read_unlock(); return NOTIFY_DONE; /* bearer had been disabled */ + } - ib_ptr->bearer->mtu = dev->mtu; + b_ptr->mtu = dev->mtu; switch (evt) { case NETDEV_CHANGE: @@ -258,13 +264,15 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, case NETDEV_DOWN: case NETDEV_CHANGEMTU: case NETDEV_CHANGEADDR: - tipc_reset_bearer(ib_ptr->bearer); + tipc_reset_bearer(b_ptr); break; case NETDEV_UNREGISTER: case NETDEV_CHANGENAME: - tipc_disable_bearer(ib_ptr->bearer->name); + tipc_disable_bearer(b_ptr->name); break; } + rcu_read_unlock(); + return NOTIFY_OK; } -- cgit v1.2.3-59-g8ed1b From b46d0c46ccaa366a5bb8ac709fdf2bcaa76221fd Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 2 Dec 2013 12:14:40 -0800 Subject: init.h: add missing initcall variants Add missing initcall variants when building for loadable modules. This fixes this build error on powerpc allmodconfig: drivers/tty/ehv_bytechan.c: error: type defaults to 'int' in declaration of 'console_initcall' [-Werror=implicit-int] Signed-off-by: Randy Dunlap Reported-by: Geert Uytterhoeven Cc: Benjamin Herrenschmidt Acked-by: Timur Tabi Signed-off-by: Greg Kroah-Hartman --- include/linux/init.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include/linux') diff --git a/include/linux/init.h b/include/linux/init.h index 8e68a64bfe00..e1688802964f 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -286,9 +286,11 @@ void __init parse_early_options(char *cmdline); #define arch_initcall(fn) module_init(fn) #define subsys_initcall(fn) module_init(fn) #define fs_initcall(fn) module_init(fn) +#define rootfs_initcall(fn) module_init(fn) #define device_initcall(fn) module_init(fn) #define late_initcall(fn) module_init(fn) +#define console_initcall(fn) module_init(fn) #define security_initcall(fn) module_init(fn) /* Each module must use one module_init(). */ -- cgit v1.2.3-59-g8ed1b From a626e64e0bee4fb26848dbed92223dde488f3d93 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 10 Jul 2013 12:03:30 -0300 Subject: [media] v4l: vsp1: Add SRU support The Super Resolution Unit performs super resolution processing with optional upscaling by a factor of two. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/Makefile | 3 +- drivers/media/platform/vsp1/vsp1.h | 2 + drivers/media/platform/vsp1/vsp1_drv.c | 11 + drivers/media/platform/vsp1/vsp1_entity.c | 4 + drivers/media/platform/vsp1/vsp1_entity.h | 1 + drivers/media/platform/vsp1/vsp1_regs.h | 13 ++ drivers/media/platform/vsp1/vsp1_sru.c | 356 ++++++++++++++++++++++++++++++ drivers/media/platform/vsp1/vsp1_sru.h | 41 ++++ include/linux/platform_data/vsp1.h | 1 + 9 files changed, 431 insertions(+), 1 deletion(-) create mode 100644 drivers/media/platform/vsp1/vsp1_sru.c create mode 100644 drivers/media/platform/vsp1/vsp1_sru.h (limited to 'include/linux') diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile index 587b8009b357..45621cb8b2a6 100644 --- a/drivers/media/platform/vsp1/Makefile +++ b/drivers/media/platform/vsp1/Makefile @@ -1,5 +1,6 @@ vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o -vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_uds.o +vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_sru.o +vsp1-y += vsp1_uds.o obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 275286e0bf42..2ab13f53b2a4 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -31,6 +31,7 @@ struct vsp1_platform_data; struct vsp1_hsit; struct vsp1_lif; struct vsp1_rwpf; +struct vsp1_sru; struct vsp1_uds; #define VPS1_MAX_RPF 5 @@ -52,6 +53,7 @@ struct vsp1_device { struct vsp1_hsit *hst; struct vsp1_lif *lif; struct vsp1_rwpf *rpf[VPS1_MAX_RPF]; + struct vsp1_sru *sru; struct vsp1_uds *uds[VPS1_MAX_UDS]; struct vsp1_rwpf *wpf[VPS1_MAX_WPF]; diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index bcede46c4a95..6f8295128704 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -23,6 +23,7 @@ #include "vsp1_hsit.h" #include "vsp1_lif.h" #include "vsp1_rwpf.h" +#include "vsp1_sru.h" #include "vsp1_uds.h" /* ----------------------------------------------------------------------------- @@ -192,6 +193,16 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&rpf->entity.list_dev, &vsp1->entities); } + if (vsp1->pdata->features & VSP1_HAS_SRU) { + vsp1->sru = vsp1_sru_create(vsp1); + if (IS_ERR(vsp1->sru)) { + ret = PTR_ERR(vsp1->sru); + goto done; + } + + list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities); + } + for (i = 0; i < vsp1->pdata->uds_count; ++i) { struct vsp1_uds *uds; diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index 3798ef4a272b..b11e5a6ffe04 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -15,6 +15,7 @@ #include #include +#include #include #include "vsp1.h" @@ -130,6 +131,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, { VI6_DPR_NODE_RPF(2), VI6_DPR_RPF_ROUTE(2) }, { VI6_DPR_NODE_RPF(3), VI6_DPR_RPF_ROUTE(3) }, { VI6_DPR_NODE_RPF(4), VI6_DPR_RPF_ROUTE(4) }, + { VI6_DPR_NODE_SRU, VI6_DPR_SRU_ROUTE }, { VI6_DPR_NODE_UDS(0), VI6_DPR_UDS_ROUTE(0) }, { VI6_DPR_NODE_UDS(1), VI6_DPR_UDS_ROUTE(1) }, { VI6_DPR_NODE_UDS(2), VI6_DPR_UDS_ROUTE(2) }, @@ -179,5 +181,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, void vsp1_entity_destroy(struct vsp1_entity *entity) { + if (entity->subdev.ctrl_handler) + v4l2_ctrl_handler_free(entity->subdev.ctrl_handler); media_entity_cleanup(&entity->subdev.entity); } diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index 0d617467066b..08e44801ec9d 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -24,6 +24,7 @@ enum vsp1_entity_type { VSP1_ENTITY_HST, VSP1_ENTITY_LIF, VSP1_ENTITY_RPF, + VSP1_ENTITY_SRU, VSP1_ENTITY_UDS, VSP1_ENTITY_WPF, }; diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 0b93f8827916..530cc61cfcd5 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -336,8 +336,21 @@ */ #define VI6_SRU_CTRL0 0x2200 +#define VI6_SRU_CTRL0_PARAM0_SHIFT 16 +#define VI6_SRU_CTRL0_PARAM1_SHIFT 8 +#define VI6_SRU_CTRL0_MODE_UPSCALE (4 << 4) +#define VI6_SRU_CTRL0_PARAM2 (1 << 3) +#define VI6_SRU_CTRL0_PARAM3 (1 << 2) +#define VI6_SRU_CTRL0_PARAM4 (1 << 1) +#define VI6_SRU_CTRL0_EN (1 << 0) + #define VI6_SRU_CTRL1 0x2204 +#define VI6_SRU_CTRL1_PARAM5 0x7ff + #define VI6_SRU_CTRL2 0x2208 +#define VI6_SRU_CTRL2_PARAM6_SHIFT 16 +#define VI6_SRU_CTRL2_PARAM7_SHIFT 8 +#define VI6_SRU_CTRL2_PARAM8_SHIFT 0 /* ----------------------------------------------------------------------------- * UDS Control Registers diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c new file mode 100644 index 000000000000..7ab1a0b2d656 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_sru.c @@ -0,0 +1,356 @@ +/* + * vsp1_sru.c -- R-Car VSP1 Super Resolution Unit + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include + +#include + +#include "vsp1.h" +#include "vsp1_sru.h" + +#define SRU_MIN_SIZE 4U +#define SRU_MAX_SIZE 8190U + +/* ----------------------------------------------------------------------------- + * Device Access + */ + +static inline u32 vsp1_sru_read(struct vsp1_sru *sru, u32 reg) +{ + return vsp1_read(sru->entity.vsp1, reg); +} + +static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data) +{ + vsp1_write(sru->entity.vsp1, reg, data); +} + +/* ----------------------------------------------------------------------------- + * Controls + */ + +#define V4L2_CID_VSP1_SRU_INTENSITY (V4L2_CID_USER_BASE + 1) + +static int sru_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vsp1_sru *sru = + container_of(ctrl->handler, struct vsp1_sru, ctrls); + + switch (ctrl->id) { + case V4L2_CID_VSP1_SRU_INTENSITY: + sru->intensity = ctrl->val; + break; + } + + return 0; +} + +static const struct v4l2_ctrl_ops sru_ctrl_ops = { + .s_ctrl = sru_s_ctrl, +}; + +static const struct v4l2_ctrl_config sru_intensity_control = { + .ops = &sru_ctrl_ops, + .id = V4L2_CID_VSP1_SRU_INTENSITY, + .name = "Intensity", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 1, + .max = 6, + .step = 1, +}; + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Core Operations + */ + +struct vsp1_sru_param { + u32 ctrl0; + u32 ctrl2; +}; + +#define VI6_SRU_CTRL0_PARAMS(p0, p1) \ + (((p0) << VI6_SRU_CTRL0_PARAM0_SHIFT) | \ + ((p1) << VI6_SRU_CTRL0_PARAM1_SHIFT)) + +#define VI6_SRU_CTRL2_PARAMS(p6, p7, p8) \ + (((p6) << VI6_SRU_CTRL2_PARAM6_SHIFT) | \ + ((p7) << VI6_SRU_CTRL2_PARAM7_SHIFT) | \ + ((p8) << VI6_SRU_CTRL2_PARAM8_SHIFT)) + +static const struct vsp1_sru_param vsp1_sru_params[] = { + { + .ctrl0 = VI6_SRU_CTRL0_PARAMS(256, 4) | VI6_SRU_CTRL0_EN, + .ctrl2 = VI6_SRU_CTRL2_PARAMS(24, 40, 255), + }, { + .ctrl0 = VI6_SRU_CTRL0_PARAMS(256, 4) | VI6_SRU_CTRL0_EN, + .ctrl2 = VI6_SRU_CTRL2_PARAMS(8, 16, 255), + }, { + .ctrl0 = VI6_SRU_CTRL0_PARAMS(384, 5) | VI6_SRU_CTRL0_EN, + .ctrl2 = VI6_SRU_CTRL2_PARAMS(36, 60, 255), + }, { + .ctrl0 = VI6_SRU_CTRL0_PARAMS(384, 5) | VI6_SRU_CTRL0_EN, + .ctrl2 = VI6_SRU_CTRL2_PARAMS(12, 27, 255), + }, { + .ctrl0 = VI6_SRU_CTRL0_PARAMS(511, 6) | VI6_SRU_CTRL0_EN, + .ctrl2 = VI6_SRU_CTRL2_PARAMS(48, 80, 255), + }, { + .ctrl0 = VI6_SRU_CTRL0_PARAMS(511, 6) | VI6_SRU_CTRL0_EN, + .ctrl2 = VI6_SRU_CTRL2_PARAMS(16, 36, 255), + }, +}; + +static int sru_s_stream(struct v4l2_subdev *subdev, int enable) +{ + struct vsp1_sru *sru = to_sru(subdev); + const struct vsp1_sru_param *param; + struct v4l2_mbus_framefmt *input; + struct v4l2_mbus_framefmt *output; + bool upscale; + u32 ctrl0; + + if (!enable) + return 0; + + input = &sru->entity.formats[SRU_PAD_SINK]; + output = &sru->entity.formats[SRU_PAD_SOURCE]; + upscale = input->width != output->width; + param = &vsp1_sru_params[sru->intensity]; + + if (input->code == V4L2_MBUS_FMT_ARGB8888_1X32) + ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3 + | VI6_SRU_CTRL0_PARAM4; + else + ctrl0 = VI6_SRU_CTRL0_PARAM3; + + vsp1_sru_write(sru, VI6_SRU_CTRL0, param->ctrl0 | ctrl0 | + (upscale ? VI6_SRU_CTRL0_MODE_UPSCALE : 0)); + vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5); + vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Pad Operations + */ + +static int sru_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + static const unsigned int codes[] = { + V4L2_MBUS_FMT_ARGB8888_1X32, + V4L2_MBUS_FMT_AYUV8_1X32, + }; + struct v4l2_mbus_framefmt *format; + + if (code->pad == SRU_PAD_SINK) { + if (code->index >= ARRAY_SIZE(codes)) + return -EINVAL; + + code->code = codes[code->index]; + } else { + /* The SRU can't perform format conversion, the sink format is + * always identical to the source format. + */ + if (code->index) + return -EINVAL; + + format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK); + code->code = format->code; + } + + return 0; +} + +static int sru_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK); + + if (fse->index || fse->code != format->code) + return -EINVAL; + + if (fse->pad == SRU_PAD_SINK) { + fse->min_width = SRU_MIN_SIZE; + fse->max_width = SRU_MAX_SIZE; + fse->min_height = SRU_MIN_SIZE; + fse->max_height = SRU_MAX_SIZE; + } else { + fse->min_width = format->width; + fse->min_height = format->height; + if (format->width <= SRU_MAX_SIZE / 2 && + format->height <= SRU_MAX_SIZE / 2) { + fse->max_width = format->width * 2; + fse->max_height = format->height * 2; + } else { + fse->max_width = format->width; + fse->max_height = format->height; + } + } + + return 0; +} + +static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct vsp1_sru *sru = to_sru(subdev); + + fmt->format = *vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad, + fmt->which); + + return 0; +} + +static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh, + unsigned int pad, struct v4l2_mbus_framefmt *fmt, + enum v4l2_subdev_format_whence which) +{ + struct v4l2_mbus_framefmt *format; + unsigned int input_area; + unsigned int output_area; + + switch (pad) { + case SRU_PAD_SINK: + /* Default to YUV if the requested format is not supported. */ + if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 && + fmt->code != V4L2_MBUS_FMT_AYUV8_1X32) + fmt->code = V4L2_MBUS_FMT_AYUV8_1X32; + + fmt->width = clamp(fmt->width, SRU_MIN_SIZE, SRU_MAX_SIZE); + fmt->height = clamp(fmt->height, SRU_MIN_SIZE, SRU_MAX_SIZE); + break; + + case SRU_PAD_SOURCE: + /* The SRU can't perform format conversion. */ + format = vsp1_entity_get_pad_format(&sru->entity, fh, + SRU_PAD_SINK, which); + fmt->code = format->code; + + /* We can upscale by 2 in both direction, but not independently. + * Compare the input and output rectangles areas (avoiding + * integer overflows on the output): if the requested output + * area is larger than 1.5^2 the input area upscale by two, + * otherwise don't scale. + */ + input_area = format->width * format->height; + output_area = min(fmt->width, SRU_MAX_SIZE) + * min(fmt->height, SRU_MAX_SIZE); + + if (fmt->width <= SRU_MAX_SIZE / 2 && + fmt->height <= SRU_MAX_SIZE / 2 && + output_area > input_area * 9 / 4) { + fmt->width = format->width * 2; + fmt->height = format->height * 2; + } else { + fmt->width = format->width; + fmt->height = format->height; + } + break; + } + + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; +} + +static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct vsp1_sru *sru = to_sru(subdev); + struct v4l2_mbus_framefmt *format; + + sru_try_format(sru, fh, fmt->pad, &fmt->format, fmt->which); + + format = vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad, + fmt->which); + *format = fmt->format; + + if (fmt->pad == SRU_PAD_SINK) { + /* Propagate the format to the source pad. */ + format = vsp1_entity_get_pad_format(&sru->entity, fh, + SRU_PAD_SOURCE, fmt->which); + *format = fmt->format; + + sru_try_format(sru, fh, SRU_PAD_SOURCE, format, fmt->which); + } + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Operations + */ + +static struct v4l2_subdev_video_ops sru_video_ops = { + .s_stream = sru_s_stream, +}; + +static struct v4l2_subdev_pad_ops sru_pad_ops = { + .enum_mbus_code = sru_enum_mbus_code, + .enum_frame_size = sru_enum_frame_size, + .get_fmt = sru_get_format, + .set_fmt = sru_set_format, +}; + +static struct v4l2_subdev_ops sru_ops = { + .video = &sru_video_ops, + .pad = &sru_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * Initialization and Cleanup + */ + +struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1) +{ + struct v4l2_subdev *subdev; + struct vsp1_sru *sru; + int ret; + + sru = devm_kzalloc(vsp1->dev, sizeof(*sru), GFP_KERNEL); + if (sru == NULL) + return ERR_PTR(-ENOMEM); + + sru->entity.type = VSP1_ENTITY_SRU; + sru->entity.id = VI6_DPR_NODE_SRU; + + ret = vsp1_entity_init(vsp1, &sru->entity, 2); + if (ret < 0) + return ERR_PTR(ret); + + /* Initialize the V4L2 subdev. */ + subdev = &sru->entity.subdev; + v4l2_subdev_init(subdev, &sru_ops); + + subdev->entity.ops = &vsp1_media_ops; + subdev->internal_ops = &vsp1_subdev_internal_ops; + snprintf(subdev->name, sizeof(subdev->name), "%s sru", + dev_name(vsp1->dev)); + v4l2_set_subdevdata(subdev, sru); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + vsp1_entity_init_formats(subdev, NULL); + + /* Initialize the control handler. */ + v4l2_ctrl_handler_init(&sru->ctrls, 1); + v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL); + v4l2_ctrl_handler_setup(&sru->ctrls); + sru->entity.subdev.ctrl_handler = &sru->ctrls; + + return sru; +} diff --git a/drivers/media/platform/vsp1/vsp1_sru.h b/drivers/media/platform/vsp1/vsp1_sru.h new file mode 100644 index 000000000000..381870b74780 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_sru.h @@ -0,0 +1,41 @@ +/* + * vsp1_sru.h -- R-Car VSP1 Super Resolution Unit + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __VSP1_SRU_H__ +#define __VSP1_SRU_H__ + +#include +#include +#include + +#include "vsp1_entity.h" + +struct vsp1_device; + +#define SRU_PAD_SINK 0 +#define SRU_PAD_SOURCE 1 + +struct vsp1_sru { + struct vsp1_entity entity; + + struct v4l2_ctrl_handler ctrls; + unsigned int intensity; +}; + +static inline struct vsp1_sru *to_sru(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct vsp1_sru, entity.subdev); +} + +struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1); + +#endif /* __VSP1_SRU_H__ */ diff --git a/include/linux/platform_data/vsp1.h b/include/linux/platform_data/vsp1.h index a73a456d7f11..27c0ede1a53f 100644 --- a/include/linux/platform_data/vsp1.h +++ b/include/linux/platform_data/vsp1.h @@ -14,6 +14,7 @@ #define __PLATFORM_VSP1_H__ #define VSP1_HAS_LIF (1 << 0) +#define VSP1_HAS_SRU (1 << 1) struct vsp1_platform_data { unsigned int features; -- cgit v1.2.3-59-g8ed1b From 989af88339db26345e23271dae1089d949c4a0f1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 10 Jul 2013 12:03:30 -0300 Subject: [media] v4l: vsp1: Add LUT support The Look-Up Table looks up values in 8-bit indexed tables separately for each color component. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/Makefile | 4 +- drivers/media/platform/vsp1/vsp1.h | 2 + drivers/media/platform/vsp1/vsp1_drv.c | 11 ++ drivers/media/platform/vsp1/vsp1_entity.c | 1 + drivers/media/platform/vsp1/vsp1_entity.h | 1 + drivers/media/platform/vsp1/vsp1_lut.c | 252 ++++++++++++++++++++++++++++++ drivers/media/platform/vsp1/vsp1_lut.h | 38 +++++ drivers/media/platform/vsp1/vsp1_regs.h | 1 + include/linux/platform_data/vsp1.h | 3 +- include/uapi/linux/vsp1.h | 34 ++++ 10 files changed, 344 insertions(+), 3 deletions(-) create mode 100644 drivers/media/platform/vsp1/vsp1_lut.c create mode 100644 drivers/media/platform/vsp1/vsp1_lut.h create mode 100644 include/uapi/linux/vsp1.h (limited to 'include/linux') diff --git a/drivers/media/platform/vsp1/Makefile b/drivers/media/platform/vsp1/Makefile index 45621cb8b2a6..151cecd0ea25 100644 --- a/drivers/media/platform/vsp1/Makefile +++ b/drivers/media/platform/vsp1/Makefile @@ -1,6 +1,6 @@ vsp1-y := vsp1_drv.o vsp1_entity.o vsp1_video.o vsp1-y += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o -vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_sru.o -vsp1-y += vsp1_uds.o +vsp1-y += vsp1_hsit.o vsp1_lif.o vsp1_lut.o +vsp1-y += vsp1_sru.o vsp1_uds.o obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1.o diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h index 2ab13f53b2a4..94d1b02680c5 100644 --- a/drivers/media/platform/vsp1/vsp1.h +++ b/drivers/media/platform/vsp1/vsp1.h @@ -30,6 +30,7 @@ struct device; struct vsp1_platform_data; struct vsp1_hsit; struct vsp1_lif; +struct vsp1_lut; struct vsp1_rwpf; struct vsp1_sru; struct vsp1_uds; @@ -52,6 +53,7 @@ struct vsp1_device { struct vsp1_hsit *hsi; struct vsp1_hsit *hst; struct vsp1_lif *lif; + struct vsp1_lut *lut; struct vsp1_rwpf *rpf[VPS1_MAX_RPF]; struct vsp1_sru *sru; struct vsp1_uds *uds[VPS1_MAX_UDS]; diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 6f8295128704..0df0a994e575 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -22,6 +22,7 @@ #include "vsp1.h" #include "vsp1_hsit.h" #include "vsp1_lif.h" +#include "vsp1_lut.h" #include "vsp1_rwpf.h" #include "vsp1_sru.h" #include "vsp1_uds.h" @@ -180,6 +181,16 @@ static int vsp1_create_entities(struct vsp1_device *vsp1) list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities); } + if (vsp1->pdata->features & VSP1_HAS_LUT) { + vsp1->lut = vsp1_lut_create(vsp1); + if (IS_ERR(vsp1->lut)) { + ret = PTR_ERR(vsp1->lut); + goto done; + } + + list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities); + } + for (i = 0; i < vsp1->pdata->rpf_count; ++i) { struct vsp1_rwpf *rpf; diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index b11e5a6ffe04..0226e47df6d9 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -126,6 +126,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, { VI6_DPR_NODE_HSI, VI6_DPR_HSI_ROUTE }, { VI6_DPR_NODE_HST, VI6_DPR_HST_ROUTE }, { VI6_DPR_NODE_LIF, 0 }, + { VI6_DPR_NODE_LUT, VI6_DPR_LUT_ROUTE }, { VI6_DPR_NODE_RPF(0), VI6_DPR_RPF_ROUTE(0) }, { VI6_DPR_NODE_RPF(1), VI6_DPR_RPF_ROUTE(1) }, { VI6_DPR_NODE_RPF(2), VI6_DPR_RPF_ROUTE(2) }, diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index 08e44801ec9d..e152798d7f38 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -23,6 +23,7 @@ enum vsp1_entity_type { VSP1_ENTITY_HSI, VSP1_ENTITY_HST, VSP1_ENTITY_LIF, + VSP1_ENTITY_LUT, VSP1_ENTITY_RPF, VSP1_ENTITY_SRU, VSP1_ENTITY_UDS, diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c new file mode 100644 index 000000000000..4e9dc7c86ef8 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_lut.c @@ -0,0 +1,252 @@ +/* + * vsp1_lut.c -- R-Car VSP1 Look-Up Table + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include + +#include + +#include "vsp1.h" +#include "vsp1_lut.h" + +#define LUT_MIN_SIZE 4U +#define LUT_MAX_SIZE 8190U + +/* ----------------------------------------------------------------------------- + * Device Access + */ + +static inline u32 vsp1_lut_read(struct vsp1_lut *lut, u32 reg) +{ + return vsp1_read(lut->entity.vsp1, reg); +} + +static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data) +{ + vsp1_write(lut->entity.vsp1, reg, data); +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Core Operations + */ + +static void lut_configure(struct vsp1_lut *lut, struct vsp1_lut_config *config) +{ + memcpy_toio(lut->entity.vsp1->mmio + VI6_LUT_TABLE, config->lut, + sizeof(config->lut)); +} + +static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg) +{ + struct vsp1_lut *lut = to_lut(subdev); + + switch (cmd) { + case VIDIOC_VSP1_LUT_CONFIG: + lut_configure(lut, arg); + return 0; + + default: + return -ENOIOCTLCMD; + } +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Video Operations + */ + +static int lut_s_stream(struct v4l2_subdev *subdev, int enable) +{ + struct vsp1_lut *lut = to_lut(subdev); + + if (!enable) + return 0; + + vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN); + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Pad Operations + */ + +static int lut_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + static const unsigned int codes[] = { + V4L2_MBUS_FMT_ARGB8888_1X32, + V4L2_MBUS_FMT_AHSV8888_1X32, + V4L2_MBUS_FMT_AYUV8_1X32, + }; + struct v4l2_mbus_framefmt *format; + + if (code->pad == LUT_PAD_SINK) { + if (code->index >= ARRAY_SIZE(codes)) + return -EINVAL; + + code->code = codes[code->index]; + } else { + /* The LUT can't perform format conversion, the sink format is + * always identical to the source format. + */ + if (code->index) + return -EINVAL; + + format = v4l2_subdev_get_try_format(fh, LUT_PAD_SINK); + code->code = format->code; + } + + return 0; +} + +static int lut_enum_frame_size(struct v4l2_subdev *subdev, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct v4l2_mbus_framefmt *format; + + format = v4l2_subdev_get_try_format(fh, fse->pad); + + if (fse->index || fse->code != format->code) + return -EINVAL; + + if (fse->pad == LUT_PAD_SINK) { + fse->min_width = LUT_MIN_SIZE; + fse->max_width = LUT_MAX_SIZE; + fse->min_height = LUT_MIN_SIZE; + fse->max_height = LUT_MAX_SIZE; + } else { + /* The size on the source pad are fixed and always identical to + * the size on the sink pad. + */ + fse->min_width = format->width; + fse->max_width = format->width; + fse->min_height = format->height; + fse->max_height = format->height; + } + + return 0; +} + +static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct vsp1_lut *lut = to_lut(subdev); + + fmt->format = *vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad, + fmt->which); + + return 0; +} + +static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct vsp1_lut *lut = to_lut(subdev); + struct v4l2_mbus_framefmt *format; + + /* Default to YUV if the requested format is not supported. */ + if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 && + fmt->format.code != V4L2_MBUS_FMT_AHSV8888_1X32 && + fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32) + fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32; + + format = vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad, + fmt->which); + + if (fmt->pad == LUT_PAD_SOURCE) { + /* The LUT output format can't be modified. */ + fmt->format = *format; + return 0; + } + + format->width = clamp_t(unsigned int, fmt->format.width, + LUT_MIN_SIZE, LUT_MAX_SIZE); + format->height = clamp_t(unsigned int, fmt->format.height, + LUT_MIN_SIZE, LUT_MAX_SIZE); + format->field = V4L2_FIELD_NONE; + format->colorspace = V4L2_COLORSPACE_SRGB; + + fmt->format = *format; + + /* Propagate the format to the source pad. */ + format = vsp1_entity_get_pad_format(&lut->entity, fh, LUT_PAD_SOURCE, + fmt->which); + *format = fmt->format; + + return 0; +} + +/* ----------------------------------------------------------------------------- + * V4L2 Subdevice Operations + */ + +static struct v4l2_subdev_core_ops lut_core_ops = { + .ioctl = lut_ioctl, +}; + +static struct v4l2_subdev_video_ops lut_video_ops = { + .s_stream = lut_s_stream, +}; + +static struct v4l2_subdev_pad_ops lut_pad_ops = { + .enum_mbus_code = lut_enum_mbus_code, + .enum_frame_size = lut_enum_frame_size, + .get_fmt = lut_get_format, + .set_fmt = lut_set_format, +}; + +static struct v4l2_subdev_ops lut_ops = { + .core = &lut_core_ops, + .video = &lut_video_ops, + .pad = &lut_pad_ops, +}; + +/* ----------------------------------------------------------------------------- + * Initialization and Cleanup + */ + +struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1) +{ + struct v4l2_subdev *subdev; + struct vsp1_lut *lut; + int ret; + + lut = devm_kzalloc(vsp1->dev, sizeof(*lut), GFP_KERNEL); + if (lut == NULL) + return ERR_PTR(-ENOMEM); + + lut->entity.type = VSP1_ENTITY_LUT; + lut->entity.id = VI6_DPR_NODE_LUT; + + ret = vsp1_entity_init(vsp1, &lut->entity, 2); + if (ret < 0) + return ERR_PTR(ret); + + /* Initialize the V4L2 subdev. */ + subdev = &lut->entity.subdev; + v4l2_subdev_init(subdev, &lut_ops); + + subdev->entity.ops = &vsp1_media_ops; + subdev->internal_ops = &vsp1_subdev_internal_ops; + snprintf(subdev->name, sizeof(subdev->name), "%s lut", + dev_name(vsp1->dev)); + v4l2_set_subdevdata(subdev, lut); + subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + + vsp1_entity_init_formats(subdev, NULL); + + return lut; +} diff --git a/drivers/media/platform/vsp1/vsp1_lut.h b/drivers/media/platform/vsp1/vsp1_lut.h new file mode 100644 index 000000000000..f92ffb867350 --- /dev/null +++ b/drivers/media/platform/vsp1/vsp1_lut.h @@ -0,0 +1,38 @@ +/* + * vsp1_lut.h -- R-Car VSP1 Look-Up Table + * + * Copyright (C) 2013 Renesas Corporation + * + * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ +#ifndef __VSP1_LUT_H__ +#define __VSP1_LUT_H__ + +#include +#include + +#include "vsp1_entity.h" + +struct vsp1_device; + +#define LUT_PAD_SINK 0 +#define LUT_PAD_SOURCE 1 + +struct vsp1_lut { + struct vsp1_entity entity; + u32 lut[256]; +}; + +static inline struct vsp1_lut *to_lut(struct v4l2_subdev *subdev) +{ + return container_of(subdev, struct vsp1_lut, entity.subdev); +} + +struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1); + +#endif /* __VSP1_LUT_H__ */ diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 530cc61cfcd5..28650806c20f 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -425,6 +425,7 @@ */ #define VI6_LUT_CTRL 0x2800 +#define VI6_LUT_CTRL_EN (1 << 0) /* ----------------------------------------------------------------------------- * CLU Control Registers diff --git a/include/linux/platform_data/vsp1.h b/include/linux/platform_data/vsp1.h index 27c0ede1a53f..63170e2614b3 100644 --- a/include/linux/platform_data/vsp1.h +++ b/include/linux/platform_data/vsp1.h @@ -14,7 +14,8 @@ #define __PLATFORM_VSP1_H__ #define VSP1_HAS_LIF (1 << 0) -#define VSP1_HAS_SRU (1 << 1) +#define VSP1_HAS_LUT (1 << 1) +#define VSP1_HAS_SRU (1 << 2) struct vsp1_platform_data { unsigned int features; diff --git a/include/uapi/linux/vsp1.h b/include/uapi/linux/vsp1.h new file mode 100644 index 000000000000..e18858f6e865 --- /dev/null +++ b/include/uapi/linux/vsp1.h @@ -0,0 +1,34 @@ +/* + * vsp1.h + * + * Renesas R-Car VSP1 - User-space API + * + * Copyright (C) 2013 Renesas Corporation + * + * Contacts: Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __VSP1_USER_H__ +#define __VSP1_USER_H__ + +#include +#include + +/* + * Private IOCTLs + * + * VIDIOC_VSP1_LUT_CONFIG - Configure the lookup table + */ + +#define VIDIOC_VSP1_LUT_CONFIG \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct vsp1_lut_config) + +struct vsp1_lut_config { + u32 lut[256]; +}; + +#endif /* __VSP1_USER_H__ */ -- cgit v1.2.3-59-g8ed1b From 98b32decc83ed3137e3ddbc918b102f8fc406b6d Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Fri, 6 Dec 2013 08:56:16 -0800 Subject: nfc: Fix FSF address in file headers Several files refer to an old address for the Free Software Foundation in the file header comment. Resolve by replacing the address with the URL so that we do not have to keep updating the header comments anytime the address changes. CC: linux-wireless@vger.kernel.org CC: Lauro Ramos Venancio CC: Aloisio Almeida Jr CC: Samuel Ortiz Signed-off-by: Jeff Kirsher Signed-off-by: John W. Linville --- drivers/nfc/mei_phy.c | 4 +--- drivers/nfc/microread/i2c.c | 4 +--- drivers/nfc/microread/mei.c | 4 +--- drivers/nfc/microread/microread.c | 4 +--- drivers/nfc/microread/microread.h | 4 +--- drivers/nfc/nfcwilink.c | 3 +-- drivers/nfc/pn533.c | 4 +--- drivers/nfc/pn544/i2c.c | 4 +--- drivers/nfc/pn544/mei.c | 4 +--- drivers/nfc/pn544/pn544.c | 4 +--- drivers/nfc/pn544/pn544.h | 4 +--- include/linux/platform_data/pn544.h | 3 +-- net/nfc/af_nfc.c | 4 +--- net/nfc/core.c | 4 +--- net/nfc/hci/command.c | 4 +--- net/nfc/hci/core.c | 4 +--- net/nfc/hci/hci.h | 4 +--- net/nfc/hci/hcp.c | 4 +--- net/nfc/hci/llc.c | 4 +--- net/nfc/hci/llc.h | 4 +--- net/nfc/hci/llc_nop.c | 4 +--- net/nfc/hci/llc_shdlc.c | 4 +--- net/nfc/llcp.h | 4 +--- net/nfc/llcp_commands.c | 4 +--- net/nfc/llcp_core.c | 4 +--- net/nfc/llcp_sock.c | 4 +--- net/nfc/nci/core.c | 3 +-- net/nfc/nci/data.c | 3 +-- net/nfc/nci/lib.c | 3 +-- net/nfc/nci/ntf.c | 3 +-- net/nfc/nci/rsp.c | 3 +-- net/nfc/netlink.c | 4 +--- net/nfc/nfc.h | 4 +--- net/nfc/rawsock.c | 4 +--- 34 files changed, 34 insertions(+), 95 deletions(-) (limited to 'include/linux') diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c index 85f90090cc1d..1d7860551985 100644 --- a/drivers/nfc/mei_phy.c +++ b/drivers/nfc/mei_phy.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c index 696e3467eccc..df85cd3d9db0 100644 --- a/drivers/nfc/microread/i2c.c +++ b/drivers/nfc/microread/i2c.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/nfc/microread/mei.c b/drivers/nfc/microread/mei.c index 72fafec3d460..2d1395be64ae 100644 --- a/drivers/nfc/microread/mei.c +++ b/drivers/nfc/microread/mei.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c index 970ded6bfcf5..f868333271aa 100644 --- a/drivers/nfc/microread/microread.c +++ b/drivers/nfc/microread/microread.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/nfc/microread/microread.h b/drivers/nfc/microread/microread.h index 64b447a1c5bf..f538641431a2 100644 --- a/drivers/nfc/microread/microread.h +++ b/drivers/nfc/microread/microread.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __LOCAL_MICROREAD_H_ diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c index 71308645593f..683671a71c7e 100644 --- a/drivers/nfc/nfcwilink.c +++ b/drivers/nfc/nfcwilink.c @@ -22,8 +22,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ #include diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 2daf04c07338..3df19e657bc1 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index b158ee1c2ac6..d6185ff2f87b 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/nfc/pn544/mei.c b/drivers/nfc/pn544/mei.c index ee67de50c36f..330cd4031009 100644 --- a/drivers/nfc/pn544/mei.c +++ b/drivers/nfc/pn544/mei.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c index 74cfa0a88b9e..51e21a87cd84 100644 --- a/drivers/nfc/pn544/pn544.c +++ b/drivers/nfc/pn544/pn544.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt diff --git a/drivers/nfc/pn544/pn544.h b/drivers/nfc/pn544/pn544.h index 01020e585443..491bf45da358 100644 --- a/drivers/nfc/pn544/pn544.h +++ b/drivers/nfc/pn544/pn544.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __LOCAL_PN544_H_ diff --git a/include/linux/platform_data/pn544.h b/include/linux/platform_data/pn544.h index 713bfd703342..5ce1ab983f44 100644 --- a/include/linux/platform_data/pn544.h +++ b/include/linux/platform_data/pn544.h @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . */ #ifndef _PN544_H_ diff --git a/net/nfc/af_nfc.c b/net/nfc/af_nfc.c index 9d68441e2a5a..2277276f52bc 100644 --- a/net/nfc/af_nfc.c +++ b/net/nfc/af_nfc.c @@ -16,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include diff --git a/net/nfc/core.c b/net/nfc/core.c index 872529105abc..02ab34132157 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -16,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 64f922be9281..a9f4d2e62d8d 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "hci: %s: " fmt, __func__ diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index d07ca4c5cf8c..3b9610031baa 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "hci: %s: " fmt, __func__ diff --git a/net/nfc/hci/hci.h b/net/nfc/hci/hci.h index b274d12c18ac..c3d2e2c1394c 100644 --- a/net/nfc/hci/hci.h +++ b/net/nfc/hci/hci.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __LOCAL_HCI_H diff --git a/net/nfc/hci/hcp.c b/net/nfc/hci/hcp.c index b6b4109f2343..e9de1514656e 100644 --- a/net/nfc/hci/hcp.c +++ b/net/nfc/hci/hcp.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "hci: %s: " fmt, __func__ diff --git a/net/nfc/hci/llc.c b/net/nfc/hci/llc.c index fe5e966e5b88..a07d2b818487 100644 --- a/net/nfc/hci/llc.c +++ b/net/nfc/hci/llc.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include diff --git a/net/nfc/hci/llc.h b/net/nfc/hci/llc.h index 7be0b7f3ceb6..5dad4c57ffb3 100644 --- a/net/nfc/hci/llc.h +++ b/net/nfc/hci/llc.h @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __LOCAL_LLC_H_ diff --git a/net/nfc/hci/llc_nop.c b/net/nfc/hci/llc_nop.c index 87b10291b40f..d0435d5a197b 100644 --- a/net/nfc/hci/llc_nop.c +++ b/net/nfc/hci/llc_nop.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #include diff --git a/net/nfc/hci/llc_shdlc.c b/net/nfc/hci/llc_shdlc.c index 27b313befc35..719ad0ac40de 100644 --- a/net/nfc/hci/llc_shdlc.c +++ b/net/nfc/hci/llc_shdlc.c @@ -13,9 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "shdlc: %s: " fmt, __func__ diff --git a/net/nfc/llcp.h b/net/nfc/llcp.h index f4d48b57ea11..de1789e3cc82 100644 --- a/net/nfc/llcp.h +++ b/net/nfc/llcp.h @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ enum llcp_state { diff --git a/net/nfc/llcp_commands.c b/net/nfc/llcp_commands.c index 1017894807c0..693cd1aad582 100644 --- a/net/nfc/llcp_commands.c +++ b/net/nfc/llcp_commands.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ diff --git a/net/nfc/llcp_core.c b/net/nfc/llcp_core.c index 81cd3416c7d4..1349074e1ffc 100644 --- a/net/nfc/llcp_core.c +++ b/net/nfc/llcp_core.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c index 824c6056bf82..69fbc8dadba7 100644 --- a/net/nfc/llcp_sock.c +++ b/net/nfc/llcp_sock.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) "llcp: %s: " fmt, __func__ diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index b943d46a1644..f0e955e3a385 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c index 2a9399dd6c68..6c3aef852876 100644 --- a/net/nfc/nci/data.c +++ b/net/nfc/nci/data.c @@ -16,8 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/nfc/nci/lib.c b/net/nfc/nci/lib.c index 6b7fd26c68d9..ed774a2e989a 100644 --- a/net/nfc/nci/lib.c +++ b/net/nfc/nci/lib.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index b2aa98ef0927..1e905097456b 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c index dd072f38ad00..041de51ccdbe 100644 --- a/net/nfc/nci/rsp.c +++ b/net/nfc/nci/rsp.c @@ -20,8 +20,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * along with this program; if not, see . * */ diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index a9b2342d5253..ebbf6fb88b35 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -16,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index aaf606fc1faa..9d6e74f7e6b3 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h @@ -16,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #ifndef __LOCAL_NFC_H diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index 66bcd2eb5773..c27a6e86cae4 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c @@ -16,9 +16,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program; if not, see . */ #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ -- cgit v1.2.3-59-g8ed1b From c700f013adb0ec57518a7fe0163e3117659ce249 Mon Sep 17 00:00:00 2001 From: "Chen, Gong" Date: Fri, 6 Dec 2013 01:17:08 -0500 Subject: EDAC: Add an edac_report parameter to EDAC This new parameter is used to control how to report HW error reporting, especially for newer Intel platform, like Ivybridge-EX, which contains an enhanced error decoding functionality in the firmware, i.e. eMCA. Signed-off-by: Chen, Gong Acked-by: Tony Luck Link: http://lkml.kernel.org/r/1386310630-12529-2-git-send-email-gong.chen@linux.intel.com [ Boris: massage commit message. ] Signed-off-by: Borislav Petkov --- Documentation/kernel-parameters.txt | 8 ++++++++ drivers/edac/edac_stub.c | 19 +++++++++++++++++++ include/linux/edac.h | 28 ++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+) (limited to 'include/linux') diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 50680a59a2ff..453092c822f1 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -881,6 +881,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted. The xen output can only be used by Xen PV guests. + edac_report= [HW,EDAC] Control how to report EDAC event + Format: {"on" | "off" | "force"} + on: enable EDAC to report H/W event. May be overridden + by other higher priority error reporting module. + off: disable H/W event reporting through EDAC. + force: enforce the use of EDAC to report H/W event. + default: on. + ekgdboc= [X86,KGDB] Allow early kernel console debugging ekgdboc=kbd diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c index 351945fa2ecd..9d9e18aefaaa 100644 --- a/drivers/edac/edac_stub.c +++ b/drivers/edac/edac_stub.c @@ -29,6 +29,25 @@ EXPORT_SYMBOL_GPL(edac_err_assert); static atomic_t edac_subsys_valid = ATOMIC_INIT(0); +int edac_report_status = EDAC_REPORTING_ENABLED; +EXPORT_SYMBOL_GPL(edac_report_status); + +static int __init edac_report_setup(char *str) +{ + if (!str) + return -EINVAL; + + if (!strncmp(str, "on", 2)) + set_edac_report_status(EDAC_REPORTING_ENABLED); + else if (!strncmp(str, "off", 3)) + set_edac_report_status(EDAC_REPORTING_DISABLED); + else if (!strncmp(str, "force", 5)) + set_edac_report_status(EDAC_REPORTING_FORCE); + + return 0; +} +__setup("edac_report=", edac_report_setup); + /* * called to determine if there is an EDAC driver interested in * knowing an event (such as NMI) occurred diff --git a/include/linux/edac.h b/include/linux/edac.h index dbdffe8d4469..8e6c20af11a2 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h @@ -35,6 +35,34 @@ extern void edac_atomic_assert_error(void); extern struct bus_type *edac_get_sysfs_subsys(void); extern void edac_put_sysfs_subsys(void); +enum { + EDAC_REPORTING_ENABLED, + EDAC_REPORTING_DISABLED, + EDAC_REPORTING_FORCE +}; + +extern int edac_report_status; +#ifdef CONFIG_EDAC +static inline int get_edac_report_status(void) +{ + return edac_report_status; +} + +static inline void set_edac_report_status(int new) +{ + edac_report_status = new; +} +#else +static inline int get_edac_report_status(void) +{ + return EDAC_REPORTING_DISABLED; +} + +static inline void set_edac_report_status(int new) +{ +} +#endif + static inline void opstate_init(void) { switch (edac_op_state) { -- cgit v1.2.3-59-g8ed1b From b601fa197fff265bf60eaf6950d4c194da080f4a Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Tue, 10 Dec 2013 15:02:40 +0100 Subject: ipv4: fix wildcard search with inet_confirm_addr() Help of this function says: "in_dev: only on this interface, 0=any interface", but since commit 39a6d0630012 ("[NETNS]: Process inet_confirm_addr in the correct namespace."), the code supposes that it will never be NULL. This function is never called with in_dev == NULL, but it's exported and may be used by an external module. Because this patch restore the ability to call inet_confirm_addr() with in_dev == NULL, I partially revert the above commit, as suggested by Julian. CC: Julian Anastasov Signed-off-by: Nicolas Dichtel Reviewed-by: Julian Anastasov Signed-off-by: David S. Miller --- drivers/net/bonding/bonding.h | 4 ++-- include/linux/inetdevice.h | 5 ++--- net/ipv4/arp.c | 4 +++- net/ipv4/devinet.c | 9 ++++----- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index a9f4f9f4d8ce..a74c92c83ead 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -394,8 +394,8 @@ static inline __be32 bond_confirm_addr(struct net_device *dev, __be32 dst, __be3 in_dev = __in_dev_get_rcu(dev); if (in_dev) - addr = inet_confirm_addr(in_dev, dst, local, RT_SCOPE_HOST); - + addr = inet_confirm_addr(dev_net(dev), in_dev, dst, local, + RT_SCOPE_HOST); rcu_read_unlock(); return addr; } diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h index 562e5c7c5d35..0068708161ff 100644 --- a/include/linux/inetdevice.h +++ b/include/linux/inetdevice.h @@ -164,11 +164,10 @@ int devinet_ioctl(struct net *net, unsigned int cmd, void __user *); void devinet_init(void); struct in_device *inetdev_by_index(struct net *, int); __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope); -__be32 inet_confirm_addr(struct in_device *in_dev, __be32 dst, __be32 local, - int scope); +__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, __be32 dst, + __be32 local, int scope); struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, __be32 mask); - static __inline__ int inet_ifa_match(__be32 addr, struct in_ifaddr *ifa) { return !((addr^ifa->ifa_address)&ifa->ifa_mask); diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index f04185863940..b67cf805910e 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -381,6 +381,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) { + struct net *net = dev_net(in_dev->dev); int scope; switch (IN_DEV_ARP_IGNORE(in_dev)) { @@ -399,6 +400,7 @@ static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) case 3: /* Do not reply for scope host addresses */ sip = 0; scope = RT_SCOPE_LINK; + in_dev = NULL; break; case 4: /* Reserved */ case 5: @@ -410,7 +412,7 @@ static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) default: return 0; } - return !inet_confirm_addr(in_dev, sip, tip, scope); + return !inet_confirm_addr(net, in_dev, sip, tip, scope); } static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 6f49efc9d4b7..84956f5f0135 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -1240,22 +1240,21 @@ static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, /* * Confirm that local IP address exists using wildcards: - * - in_dev: only on this interface, 0=any interface + * - net: netns to check, cannot be NULL + * - in_dev: only on this interface, NULL=any interface * - dst: only in the same subnet as dst, 0=any dst * - local: address, 0=autoselect the local address * - scope: maximum allowed scope value for the local address */ -__be32 inet_confirm_addr(struct in_device *in_dev, +__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, __be32 dst, __be32 local, int scope) { __be32 addr = 0; struct net_device *dev; - struct net *net; - if (scope != RT_SCOPE_LINK) + if (in_dev != NULL) return confirm_addr_indev(in_dev, dst, local, scope); - net = dev_net(in_dev->dev); rcu_read_lock(); for_each_netdev_rcu(net, dev) { in_dev = __in_dev_get_rcu(dev); -- cgit v1.2.3-59-g8ed1b From 79b53d199b83a44811cd57091751ef122351ae85 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 10 Dec 2013 10:09:42 +0100 Subject: regulator: s5m8767: Define symbol for buck control mask Replace hard-coded value for mask used in BUCKX_CTRL registers (for BUCKX_EN field) with a symbol. This also removes two local variables. Signed-off-by: Krzysztof Kozlowski Acked-by: Lee Jones Reviewed-by: Sachin Kamat Signed-off-by: Mark Brown --- drivers/regulator/s5m8767.c | 11 ++++++----- include/linux/mfd/samsung/s5m8767.h | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index cbf91e25cf7f..ef4da4442fa7 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -217,7 +217,7 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) { struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); int ret, reg; - int mask = 0xc0, enable_ctrl; + int enable_ctrl; unsigned int val; ret = s5m8767_get_register(rdev, ®, &enable_ctrl); @@ -230,27 +230,28 @@ static int s5m8767_reg_is_enabled(struct regulator_dev *rdev) if (ret) return ret; - return (val & mask) == enable_ctrl; + return (val & S5M8767_ENCTRL_MASK) == enable_ctrl; } static int s5m8767_reg_enable(struct regulator_dev *rdev) { struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); int ret, reg; - int mask = 0xc0, enable_ctrl; + int enable_ctrl; ret = s5m8767_get_register(rdev, ®, &enable_ctrl); if (ret) return ret; - return sec_reg_update(s5m8767->iodev, reg, enable_ctrl, mask); + return sec_reg_update(s5m8767->iodev, reg, enable_ctrl, + S5M8767_ENCTRL_MASK); } static int s5m8767_reg_disable(struct regulator_dev *rdev) { struct s5m8767_info *s5m8767 = rdev_get_drvdata(rdev); int ret, reg; - int mask = 0xc0, enable_ctrl; + int mask = S5M8767_ENCTRL_MASK, enable_ctrl; ret = s5m8767_get_register(rdev, ®, &enable_ctrl); if (ret) diff --git a/include/linux/mfd/samsung/s5m8767.h b/include/linux/mfd/samsung/s5m8767.h index 306a95fc558c..9198377ee859 100644 --- a/include/linux/mfd/samsung/s5m8767.h +++ b/include/linux/mfd/samsung/s5m8767.h @@ -183,6 +183,7 @@ enum s5m8767_regulators { S5M8767_REG_MAX, }; -#define S5M8767_ENCTRL_SHIFT 6 +#define S5M8767_ENCTRL_SHIFT 6 +#define S5M8767_ENCTRL_MASK (0x3 << S5M8767_ENCTRL_SHIFT) #endif /* __LINUX_MFD_S5M8767_H */ -- cgit v1.2.3-59-g8ed1b From 324a56e16e44baecac3ca799fd216154145c14bf Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:53 -0500 Subject: kernfs: s/sysfs_dirent/kernfs_node/ and rename its friends accordingly kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. This patch performs the following renames. * s/sysfs_elem_dir/kernfs_elem_dir/ * s/sysfs_elem_symlink/kernfs_elem_symlink/ * s/sysfs_elem_attr/kernfs_elem_file/ * s/sysfs_dirent/kernfs_node/ * s/sd/kn/ in kernfs proper * s/parent_sd/parent/ * s/target_sd/target/ * s/dir_sd/parent/ * s/to_sysfs_dirent()/rb_to_kn()/ * misc renames of local vars when they conflict with the above Because md, mic and gpio dig into sysfs details, this patch ends up modifying them. All are sysfs_dirent renames and trivial. While we can avoid these by introducing a dummy wrapping struct sysfs_dirent around kernfs_node, given the limited usage outside kernfs and sysfs proper, I don't think such workaround is called for. This patch is strictly rename only and doesn't introduce any functional difference. - mic / gpio renames were missing. Spotted by kbuild test robot. Signed-off-by: Tejun Heo Cc: Neil Brown Cc: Linus Walleij Cc: Ashutosh Dixit Cc: kbuild test robot Signed-off-by: Greg Kroah-Hartman --- drivers/gpio/gpiolib.c | 4 +- drivers/md/bitmap.c | 2 +- drivers/md/bitmap.h | 2 +- drivers/md/md.h | 10 +- drivers/misc/mic/host/mic_device.h | 2 +- fs/kernfs/dir.c | 542 ++++++++++++++++++------------------- fs/kernfs/file.c | 186 ++++++------- fs/kernfs/inode.c | 123 ++++----- fs/kernfs/kernfs-internal.h | 40 +-- fs/kernfs/mount.c | 12 +- fs/kernfs/symlink.c | 64 ++--- fs/sysfs/dir.c | 66 ++--- fs/sysfs/file.c | 122 ++++----- fs/sysfs/group.c | 96 +++---- fs/sysfs/mount.c | 4 +- fs/sysfs/symlink.c | 72 ++--- fs/sysfs/sysfs.h | 10 +- include/linux/kernfs.h | 166 ++++++------ include/linux/kobject.h | 2 +- include/linux/sysfs.h | 20 +- lib/kobject.c | 2 +- 21 files changed, 774 insertions(+), 773 deletions(-) (limited to 'include/linux') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 85f772c0b26a..c8a7c810bade 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -393,7 +393,7 @@ static const DEVICE_ATTR(value, 0644, static irqreturn_t gpio_sysfs_irq(int irq, void *priv) { - struct sysfs_dirent *value_sd = priv; + struct kernfs_node *value_sd = priv; sysfs_notify_dirent(value_sd); return IRQ_HANDLED; @@ -402,7 +402,7 @@ static irqreturn_t gpio_sysfs_irq(int irq, void *priv) static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev, unsigned long gpio_flags) { - struct sysfs_dirent *value_sd; + struct kernfs_node *value_sd; unsigned long irq_flags; int ret, irq, id; diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 12dc29ba7399..4195a01b1535 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -1635,7 +1635,7 @@ int bitmap_create(struct mddev *mddev) sector_t blocks = mddev->resync_max_sectors; struct file *file = mddev->bitmap_info.file; int err; - struct sysfs_dirent *bm = NULL; + struct kernfs_node *bm = NULL; BUILD_BUG_ON(sizeof(bitmap_super_t) != 256); diff --git a/drivers/md/bitmap.h b/drivers/md/bitmap.h index df4aeb6ac6f0..30210b9c4ef9 100644 --- a/drivers/md/bitmap.h +++ b/drivers/md/bitmap.h @@ -225,7 +225,7 @@ struct bitmap { wait_queue_head_t overflow_wait; wait_queue_head_t behind_wait; - struct sysfs_dirent *sysfs_can_clear; + struct kernfs_node *sysfs_can_clear; }; /* the bitmap API */ diff --git a/drivers/md/md.h b/drivers/md/md.h index 2f5cc8a7ef3e..389a3c93cdb7 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -106,7 +106,7 @@ struct md_rdev { */ struct work_struct del_work; /* used for delayed sysfs removal */ - struct sysfs_dirent *sysfs_state; /* handle for 'state' + struct kernfs_node *sysfs_state; /* handle for 'state' * sysfs entry */ struct badblocks { @@ -376,10 +376,10 @@ struct mddev { sector_t resync_max; /* resync should pause * when it gets here */ - struct sysfs_dirent *sysfs_state; /* handle for 'array_state' + struct kernfs_node *sysfs_state; /* handle for 'array_state' * file in sysfs. */ - struct sysfs_dirent *sysfs_action; /* handle for 'sync_action' */ + struct kernfs_node *sysfs_action; /* handle for 'sync_action' */ struct work_struct del_work; /* used for delayed sysfs removal */ @@ -498,13 +498,13 @@ struct md_sysfs_entry { }; extern struct attribute_group md_bitmap_group; -static inline struct sysfs_dirent *sysfs_get_dirent_safe(struct sysfs_dirent *sd, char *name) +static inline struct kernfs_node *sysfs_get_dirent_safe(struct kernfs_node *sd, char *name) { if (sd) return sysfs_get_dirent(sd, name); return sd; } -static inline void sysfs_notify_dirent_safe(struct sysfs_dirent *sd) +static inline void sysfs_notify_dirent_safe(struct kernfs_node *sd) { if (sd) sysfs_notify_dirent(sd); diff --git a/drivers/misc/mic/host/mic_device.h b/drivers/misc/mic/host/mic_device.h index 3574cc375bb9..538e3d3d3c8c 100644 --- a/drivers/misc/mic/host/mic_device.h +++ b/drivers/misc/mic/host/mic_device.h @@ -112,7 +112,7 @@ struct mic_device { struct work_struct shutdown_work; u8 state; u8 shutdown_status; - struct sysfs_dirent *state_sysfs; + struct kernfs_node *state_sysfs; struct completion reset_wait; void *log_buf_addr; int *log_buf_len; diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index a441e3be8052..800ebf521472 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -19,7 +19,7 @@ DEFINE_MUTEX(sysfs_mutex); -#define to_sysfs_dirent(X) rb_entry((X), struct sysfs_dirent, s_rb) +#define rb_to_kn(X) rb_entry((X), struct kernfs_node, s_rb) /** * sysfs_name_hash @@ -45,28 +45,28 @@ static unsigned int sysfs_name_hash(const char *name, const void *ns) } static int sysfs_name_compare(unsigned int hash, const char *name, - const void *ns, const struct sysfs_dirent *sd) + const void *ns, const struct kernfs_node *kn) { - if (hash != sd->s_hash) - return hash - sd->s_hash; - if (ns != sd->s_ns) - return ns - sd->s_ns; - return strcmp(name, sd->s_name); + if (hash != kn->s_hash) + return hash - kn->s_hash; + if (ns != kn->s_ns) + return ns - kn->s_ns; + return strcmp(name, kn->s_name); } -static int sysfs_sd_compare(const struct sysfs_dirent *left, - const struct sysfs_dirent *right) +static int sysfs_sd_compare(const struct kernfs_node *left, + const struct kernfs_node *right) { return sysfs_name_compare(left->s_hash, left->s_name, left->s_ns, right); } /** - * sysfs_link_sibling - link sysfs_dirent into sibling rbtree - * @sd: sysfs_dirent of interest + * sysfs_link_sibling - link kernfs_node into sibling rbtree + * @kn: kernfs_node of interest * - * Link @sd into its sibling rbtree which starts from - * sd->s_parent->s_dir.children. + * Link @kn into its sibling rbtree which starts from + * @kn->s_parent->s_dir.children. * * Locking: * mutex_lock(sysfs_mutex) @@ -74,21 +74,21 @@ static int sysfs_sd_compare(const struct sysfs_dirent *left, * RETURNS: * 0 on susccess -EEXIST on failure. */ -static int sysfs_link_sibling(struct sysfs_dirent *sd) +static int sysfs_link_sibling(struct kernfs_node *kn) { - struct rb_node **node = &sd->s_parent->s_dir.children.rb_node; + struct rb_node **node = &kn->s_parent->s_dir.children.rb_node; struct rb_node *parent = NULL; - if (sysfs_type(sd) == SYSFS_DIR) - sd->s_parent->s_dir.subdirs++; + if (sysfs_type(kn) == SYSFS_DIR) + kn->s_parent->s_dir.subdirs++; while (*node) { - struct sysfs_dirent *pos; + struct kernfs_node *pos; int result; - pos = to_sysfs_dirent(*node); + pos = rb_to_kn(*node); parent = *node; - result = sysfs_sd_compare(sd, pos); + result = sysfs_sd_compare(kn, pos); if (result < 0) node = &pos->s_rb.rb_left; else if (result > 0) @@ -97,168 +97,169 @@ static int sysfs_link_sibling(struct sysfs_dirent *sd) return -EEXIST; } /* add new node and rebalance the tree */ - rb_link_node(&sd->s_rb, parent, node); - rb_insert_color(&sd->s_rb, &sd->s_parent->s_dir.children); + rb_link_node(&kn->s_rb, parent, node); + rb_insert_color(&kn->s_rb, &kn->s_parent->s_dir.children); return 0; } /** - * sysfs_unlink_sibling - unlink sysfs_dirent from sibling rbtree - * @sd: sysfs_dirent of interest + * sysfs_unlink_sibling - unlink kernfs_node from sibling rbtree + * @kn: kernfs_node of interest * - * Unlink @sd from its sibling rbtree which starts from - * sd->s_parent->s_dir.children. + * Unlink @kn from its sibling rbtree which starts from + * kn->s_parent->s_dir.children. * * Locking: * mutex_lock(sysfs_mutex) */ -static void sysfs_unlink_sibling(struct sysfs_dirent *sd) +static void sysfs_unlink_sibling(struct kernfs_node *kn) { - if (sysfs_type(sd) == SYSFS_DIR) - sd->s_parent->s_dir.subdirs--; + if (sysfs_type(kn) == SYSFS_DIR) + kn->s_parent->s_dir.subdirs--; - rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children); + rb_erase(&kn->s_rb, &kn->s_parent->s_dir.children); } /** - * sysfs_get_active - get an active reference to sysfs_dirent - * @sd: sysfs_dirent to get an active reference to + * sysfs_get_active - get an active reference to kernfs_node + * @kn: kernfs_node to get an active reference to * - * Get an active reference of @sd. This function is noop if @sd + * Get an active reference of @kn. This function is noop if @kn * is NULL. * * RETURNS: - * Pointer to @sd on success, NULL on failure. + * Pointer to @kn on success, NULL on failure. */ -struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd) +struct kernfs_node *sysfs_get_active(struct kernfs_node *kn) { - if (unlikely(!sd)) + if (unlikely(!kn)) return NULL; - if (!atomic_inc_unless_negative(&sd->s_active)) + if (!atomic_inc_unless_negative(&kn->s_active)) return NULL; - if (sd->s_flags & SYSFS_FLAG_LOCKDEP) - rwsem_acquire_read(&sd->dep_map, 0, 1, _RET_IP_); - return sd; + if (kn->s_flags & SYSFS_FLAG_LOCKDEP) + rwsem_acquire_read(&kn->dep_map, 0, 1, _RET_IP_); + return kn; } /** - * sysfs_put_active - put an active reference to sysfs_dirent - * @sd: sysfs_dirent to put an active reference to + * sysfs_put_active - put an active reference to kernfs_node + * @kn: kernfs_node to put an active reference to * - * Put an active reference to @sd. This function is noop if @sd + * Put an active reference to @kn. This function is noop if @kn * is NULL. */ -void sysfs_put_active(struct sysfs_dirent *sd) +void sysfs_put_active(struct kernfs_node *kn) { int v; - if (unlikely(!sd)) + if (unlikely(!kn)) return; - if (sd->s_flags & SYSFS_FLAG_LOCKDEP) - rwsem_release(&sd->dep_map, 1, _RET_IP_); - v = atomic_dec_return(&sd->s_active); + if (kn->s_flags & SYSFS_FLAG_LOCKDEP) + rwsem_release(&kn->dep_map, 1, _RET_IP_); + v = atomic_dec_return(&kn->s_active); if (likely(v != SD_DEACTIVATED_BIAS)) return; - /* atomic_dec_return() is a mb(), we'll always see the updated - * sd->u.completion. + /* + * atomic_dec_return() is a mb(), we'll always see the updated + * kn->u.completion. */ - complete(sd->u.completion); + complete(kn->u.completion); } /** - * sysfs_deactivate - deactivate sysfs_dirent - * @sd: sysfs_dirent to deactivate + * sysfs_deactivate - deactivate kernfs_node + * @kn: kernfs_node to deactivate * * Deny new active references and drain existing ones. */ -static void sysfs_deactivate(struct sysfs_dirent *sd) +static void sysfs_deactivate(struct kernfs_node *kn) { DECLARE_COMPLETION_ONSTACK(wait); int v; - BUG_ON(!(sd->s_flags & SYSFS_FLAG_REMOVED)); + BUG_ON(!(kn->s_flags & SYSFS_FLAG_REMOVED)); - if (!(sysfs_type(sd) & SYSFS_ACTIVE_REF)) + if (!(sysfs_type(kn) & SYSFS_ACTIVE_REF)) return; - sd->u.completion = (void *)&wait; + kn->u.completion = (void *)&wait; - rwsem_acquire(&sd->dep_map, 0, 0, _RET_IP_); + rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_); /* atomic_add_return() is a mb(), put_active() will always see - * the updated sd->u.completion. + * the updated kn->u.completion. */ - v = atomic_add_return(SD_DEACTIVATED_BIAS, &sd->s_active); + v = atomic_add_return(SD_DEACTIVATED_BIAS, &kn->s_active); if (v != SD_DEACTIVATED_BIAS) { - lock_contended(&sd->dep_map, _RET_IP_); + lock_contended(&kn->dep_map, _RET_IP_); wait_for_completion(&wait); } - lock_acquired(&sd->dep_map, _RET_IP_); - rwsem_release(&sd->dep_map, 1, _RET_IP_); + lock_acquired(&kn->dep_map, _RET_IP_); + rwsem_release(&kn->dep_map, 1, _RET_IP_); } /** - * kernfs_get - get a reference count on a sysfs_dirent - * @sd: the target sysfs_dirent + * kernfs_get - get a reference count on a kernfs_node + * @kn: the target kernfs_node */ -void kernfs_get(struct sysfs_dirent *sd) +void kernfs_get(struct kernfs_node *kn) { - if (sd) { - WARN_ON(!atomic_read(&sd->s_count)); - atomic_inc(&sd->s_count); + if (kn) { + WARN_ON(!atomic_read(&kn->s_count)); + atomic_inc(&kn->s_count); } } EXPORT_SYMBOL_GPL(kernfs_get); /** - * kernfs_put - put a reference count on a sysfs_dirent - * @sd: the target sysfs_dirent + * kernfs_put - put a reference count on a kernfs_node + * @kn: the target kernfs_node * - * Put a reference count of @sd and destroy it if it reached zero. + * Put a reference count of @kn and destroy it if it reached zero. */ -void kernfs_put(struct sysfs_dirent *sd) +void kernfs_put(struct kernfs_node *kn) { - struct sysfs_dirent *parent_sd; + struct kernfs_node *parent; struct kernfs_root *root; - if (!sd || !atomic_dec_and_test(&sd->s_count)) + if (!kn || !atomic_dec_and_test(&kn->s_count)) return; - root = kernfs_root(sd); + root = kernfs_root(kn); repeat: /* Moving/renaming is always done while holding reference. - * sd->s_parent won't change beneath us. + * kn->s_parent won't change beneath us. */ - parent_sd = sd->s_parent; + parent = kn->s_parent; - WARN(!(sd->s_flags & SYSFS_FLAG_REMOVED), + WARN(!(kn->s_flags & SYSFS_FLAG_REMOVED), "sysfs: free using entry: %s/%s\n", - parent_sd ? parent_sd->s_name : "", sd->s_name); - - if (sysfs_type(sd) == SYSFS_KOBJ_LINK) - kernfs_put(sd->s_symlink.target_sd); - if (sysfs_type(sd) & SYSFS_COPY_NAME) - kfree(sd->s_name); - if (sd->s_iattr) { - if (sd->s_iattr->ia_secdata) - security_release_secctx(sd->s_iattr->ia_secdata, - sd->s_iattr->ia_secdata_len); - simple_xattrs_free(&sd->s_iattr->xattrs); + parent ? parent->s_name : "", kn->s_name); + + if (sysfs_type(kn) == SYSFS_KOBJ_LINK) + kernfs_put(kn->s_symlink.target_kn); + if (sysfs_type(kn) & SYSFS_COPY_NAME) + kfree(kn->s_name); + if (kn->s_iattr) { + if (kn->s_iattr->ia_secdata) + security_release_secctx(kn->s_iattr->ia_secdata, + kn->s_iattr->ia_secdata_len); + simple_xattrs_free(&kn->s_iattr->xattrs); } - kfree(sd->s_iattr); - ida_simple_remove(&root->ino_ida, sd->s_ino); - kmem_cache_free(sysfs_dir_cachep, sd); + kfree(kn->s_iattr); + ida_simple_remove(&root->ino_ida, kn->s_ino); + kmem_cache_free(sysfs_dir_cachep, kn); - sd = parent_sd; - if (sd) { - if (atomic_dec_and_test(&sd->s_count)) + kn = parent; + if (kn) { + if (atomic_dec_and_test(&kn->s_count)) goto repeat; } else { - /* just released the root sd, free @root too */ + /* just released the root kn, free @root too */ ida_destroy(&root->ino_ida); kfree(root); } @@ -267,35 +268,35 @@ EXPORT_SYMBOL_GPL(kernfs_put); static int sysfs_dentry_delete(const struct dentry *dentry) { - struct sysfs_dirent *sd = dentry->d_fsdata; - return !(sd && !(sd->s_flags & SYSFS_FLAG_REMOVED)); + struct kernfs_node *kn = dentry->d_fsdata; + return !(kn && !(kn->s_flags & SYSFS_FLAG_REMOVED)); } static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) { - struct sysfs_dirent *sd; + struct kernfs_node *kn; if (flags & LOOKUP_RCU) return -ECHILD; - sd = dentry->d_fsdata; + kn = dentry->d_fsdata; mutex_lock(&sysfs_mutex); /* The sysfs dirent has been deleted */ - if (sd->s_flags & SYSFS_FLAG_REMOVED) + if (kn->s_flags & SYSFS_FLAG_REMOVED) goto out_bad; /* The sysfs dirent has been moved? */ - if (dentry->d_parent->d_fsdata != sd->s_parent) + if (dentry->d_parent->d_fsdata != kn->s_parent) goto out_bad; /* The sysfs dirent has been renamed */ - if (strcmp(dentry->d_name.name, sd->s_name) != 0) + if (strcmp(dentry->d_name.name, kn->s_name) != 0) goto out_bad; /* The sysfs dirent has been moved to a different namespace */ - if (sd->s_parent && kernfs_ns_enabled(sd->s_parent) && - sysfs_info(dentry->d_sb)->ns != sd->s_ns) + if (kn->s_parent && kernfs_ns_enabled(kn->s_parent) && + sysfs_info(dentry->d_sb)->ns != kn->s_ns) goto out_bad; mutex_unlock(&sysfs_mutex); @@ -335,11 +336,11 @@ const struct dentry_operations sysfs_dentry_ops = { .d_release = sysfs_dentry_release, }; -struct sysfs_dirent *sysfs_new_dirent(struct kernfs_root *root, - const char *name, umode_t mode, int type) +struct kernfs_node *sysfs_new_dirent(struct kernfs_root *root, + const char *name, umode_t mode, int type) { char *dup_name = NULL; - struct sysfs_dirent *sd; + struct kernfs_node *kn; int ret; if (type & SYSFS_COPY_NAME) { @@ -348,38 +349,38 @@ struct sysfs_dirent *sysfs_new_dirent(struct kernfs_root *root, return NULL; } - sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL); - if (!sd) + kn = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL); + if (!kn) goto err_out1; ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL); if (ret < 0) goto err_out2; - sd->s_ino = ret; + kn->s_ino = ret; - atomic_set(&sd->s_count, 1); - atomic_set(&sd->s_active, 0); + atomic_set(&kn->s_count, 1); + atomic_set(&kn->s_active, 0); - sd->s_name = name; - sd->s_mode = mode; - sd->s_flags = type | SYSFS_FLAG_REMOVED; + kn->s_name = name; + kn->s_mode = mode; + kn->s_flags = type | SYSFS_FLAG_REMOVED; - return sd; + return kn; err_out2: - kmem_cache_free(sysfs_dir_cachep, sd); + kmem_cache_free(sysfs_dir_cachep, kn); err_out1: kfree(dup_name); return NULL; } /** - * sysfs_addrm_start - prepare for sysfs_dirent add/remove + * sysfs_addrm_start - prepare for kernfs_node add/remove * @acxt: pointer to sysfs_addrm_cxt to be used * * This function is called when the caller is about to add or remove - * sysfs_dirent. This function acquires sysfs_mutex. @acxt is used - * to keep and pass context to other addrm functions. + * kernfs_node. This function acquires sysfs_mutex. @acxt is used to + * keep and pass context to other addrm functions. * * LOCKING: * Kernel thread context (may sleep). sysfs_mutex is locked on @@ -394,13 +395,13 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt) } /** - * sysfs_add_one - add sysfs_dirent to parent without warning + * sysfs_add_one - add kernfs_node to parent without warning * @acxt: addrm context to use - * @sd: sysfs_dirent to be added - * @parent_sd: the parent sysfs_dirent to add @sd to + * @kn: kernfs_node to be added + * @parent: the parent kernfs_node to add @kn to * - * Get @parent_sd and set @sd->s_parent to it and increment nlink of - * the parent inode if @sd is a directory and link into the children + * Get @parent and set @kn->s_parent to it and increment nlink of + * the parent inode if @kn is a directory and link into the children * list of the parent. * * This function should be called between calls to @@ -414,51 +415,51 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt) * 0 on success, -EEXIST if entry with the given name already * exists. */ -int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, - struct sysfs_dirent *parent_sd) +int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct kernfs_node *kn, + struct kernfs_node *parent) { - bool has_ns = kernfs_ns_enabled(parent_sd); + bool has_ns = kernfs_ns_enabled(parent); struct sysfs_inode_attrs *ps_iattr; int ret; - if (has_ns != (bool)sd->s_ns) { + if (has_ns != (bool)kn->s_ns) { WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", has_ns ? "required" : "invalid", - parent_sd->s_name, sd->s_name); + parent->s_name, kn->s_name); return -EINVAL; } - if (sysfs_type(parent_sd) != SYSFS_DIR) + if (sysfs_type(parent) != SYSFS_DIR) return -EINVAL; - sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); - sd->s_parent = parent_sd; - kernfs_get(parent_sd); + kn->s_hash = sysfs_name_hash(kn->s_name, kn->s_ns); + kn->s_parent = parent; + kernfs_get(parent); - ret = sysfs_link_sibling(sd); + ret = sysfs_link_sibling(kn); if (ret) return ret; /* Update timestamps on the parent */ - ps_iattr = parent_sd->s_iattr; + ps_iattr = parent->s_iattr; if (ps_iattr) { struct iattr *ps_iattrs = &ps_iattr->ia_iattr; ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; } /* Mark the entry added into directory tree */ - sd->s_flags &= ~SYSFS_FLAG_REMOVED; + kn->s_flags &= ~SYSFS_FLAG_REMOVED; return 0; } /** - * sysfs_remove_one - remove sysfs_dirent from parent + * sysfs_remove_one - remove kernfs_node from parent * @acxt: addrm context to use - * @sd: sysfs_dirent to be removed + * @kn: kernfs_node to be removed * - * Mark @sd removed and drop nlink of parent inode if @sd is a - * directory. @sd is unlinked from the children list. + * Mark @kn removed and drop nlink of parent inode if @kn is a + * directory. @kn is unlinked from the children list. * * This function should be called between calls to * sysfs_addrm_start() and sysfs_addrm_finish() and should be @@ -468,7 +469,7 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, * Determined by sysfs_addrm_start(). */ static void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, - struct sysfs_dirent *sd) + struct kernfs_node *kn) { struct sysfs_inode_attrs *ps_iattr; @@ -476,31 +477,31 @@ static void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, * Removal can be called multiple times on the same node. Only the * first invocation is effective and puts the base ref. */ - if (sd->s_flags & SYSFS_FLAG_REMOVED) + if (kn->s_flags & SYSFS_FLAG_REMOVED) return; - if (sd->s_parent) { - sysfs_unlink_sibling(sd); + if (kn->s_parent) { + sysfs_unlink_sibling(kn); /* Update timestamps on the parent */ - ps_iattr = sd->s_parent->s_iattr; + ps_iattr = kn->s_parent->s_iattr; if (ps_iattr) { ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME; ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME; } } - sd->s_flags |= SYSFS_FLAG_REMOVED; - sd->u.removed_list = acxt->removed; - acxt->removed = sd; + kn->s_flags |= SYSFS_FLAG_REMOVED; + kn->u.removed_list = acxt->removed; + acxt->removed = kn; } /** - * sysfs_addrm_finish - finish up sysfs_dirent add/remove + * sysfs_addrm_finish - finish up kernfs_node add/remove * @acxt: addrm context to finish up * - * Finish up sysfs_dirent add/remove. Resources acquired by - * sysfs_addrm_start() are released and removed sysfs_dirents are + * Finish up kernfs_node add/remove. Resources acquired by + * sysfs_addrm_start() are released and removed kernfs_nodes are * cleaned up. * * LOCKING: @@ -512,30 +513,30 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) /* release resources acquired by sysfs_addrm_start() */ mutex_unlock(&sysfs_mutex); - /* kill removed sysfs_dirents */ + /* kill removed kernfs_nodes */ while (acxt->removed) { - struct sysfs_dirent *sd = acxt->removed; + struct kernfs_node *kn = acxt->removed; - acxt->removed = sd->u.removed_list; + acxt->removed = kn->u.removed_list; - sysfs_deactivate(sd); - sysfs_unmap_bin_file(sd); - kernfs_put(sd); + sysfs_deactivate(kn); + sysfs_unmap_bin_file(kn); + kernfs_put(kn); } } /** - * kernfs_find_ns - find sysfs_dirent with the given name - * @parent: sysfs_dirent to search under + * kernfs_find_ns - find kernfs_node with the given name + * @parent: kernfs_node to search under * @name: name to look for * @ns: the namespace tag to use * - * Look for sysfs_dirent with name @name under @parent. Returns pointer to - * the found sysfs_dirent on success, %NULL on failure. + * Look for kernfs_node with name @name under @parent. Returns pointer to + * the found kernfs_node on success, %NULL on failure. */ -static struct sysfs_dirent *kernfs_find_ns(struct sysfs_dirent *parent, - const unsigned char *name, - const void *ns) +static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, + const unsigned char *name, + const void *ns) { struct rb_node *node = parent->s_dir.children.rb_node; bool has_ns = kernfs_ns_enabled(parent); @@ -552,42 +553,42 @@ static struct sysfs_dirent *kernfs_find_ns(struct sysfs_dirent *parent, hash = sysfs_name_hash(name, ns); while (node) { - struct sysfs_dirent *sd; + struct kernfs_node *kn; int result; - sd = to_sysfs_dirent(node); - result = sysfs_name_compare(hash, name, ns, sd); + kn = rb_to_kn(node); + result = sysfs_name_compare(hash, name, ns, kn); if (result < 0) node = node->rb_left; else if (result > 0) node = node->rb_right; else - return sd; + return kn; } return NULL; } /** - * kernfs_find_and_get_ns - find and get sysfs_dirent with the given name - * @parent: sysfs_dirent to search under + * kernfs_find_and_get_ns - find and get kernfs_node with the given name + * @parent: kernfs_node to search under * @name: name to look for * @ns: the namespace tag to use * - * Look for sysfs_dirent with name @name under @parent and get a reference + * Look for kernfs_node with name @name under @parent and get a reference * if found. This function may sleep and returns pointer to the found - * sysfs_dirent on success, %NULL on failure. + * kernfs_node on success, %NULL on failure. */ -struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, - const char *name, const void *ns) +struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, + const char *name, const void *ns) { - struct sysfs_dirent *sd; + struct kernfs_node *kn; mutex_lock(&sysfs_mutex); - sd = kernfs_find_ns(parent, name, ns); - kernfs_get(sd); + kn = kernfs_find_ns(parent, name, ns); + kernfs_get(kn); mutex_unlock(&sysfs_mutex); - return sd; + return kn; } EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); @@ -601,7 +602,7 @@ EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); struct kernfs_root *kernfs_create_root(void *priv) { struct kernfs_root *root; - struct sysfs_dirent *sd; + struct kernfs_node *kn; root = kzalloc(sizeof(*root), GFP_KERNEL); if (!root) @@ -609,18 +610,18 @@ struct kernfs_root *kernfs_create_root(void *priv) ida_init(&root->ino_ida); - sd = sysfs_new_dirent(root, "", S_IFDIR | S_IRUGO | S_IXUGO, SYSFS_DIR); - if (!sd) { + kn = sysfs_new_dirent(root, "", S_IFDIR | S_IRUGO | S_IXUGO, SYSFS_DIR); + if (!kn) { ida_destroy(&root->ino_ida); kfree(root); return ERR_PTR(-ENOMEM); } - sd->s_flags &= ~SYSFS_FLAG_REMOVED; - sd->priv = priv; - sd->s_dir.root = root; + kn->s_flags &= ~SYSFS_FLAG_REMOVED; + kn->priv = priv; + kn->s_dir.root = root; - root->sd = sd; + root->kn = kn; return root; } @@ -634,7 +635,7 @@ struct kernfs_root *kernfs_create_root(void *priv) */ void kernfs_destroy_root(struct kernfs_root *root) { - kernfs_remove(root->sd); /* will also free @root */ + kernfs_remove(root->kn); /* will also free @root */ } /** @@ -646,33 +647,33 @@ void kernfs_destroy_root(struct kernfs_root *root) * * Returns the created node on success, ERR_PTR() value on failure. */ -struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, - const char *name, void *priv, - const void *ns) +struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, + const char *name, void *priv, + const void *ns) { umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; struct sysfs_addrm_cxt acxt; - struct sysfs_dirent *sd; + struct kernfs_node *kn; int rc; /* allocate */ - sd = sysfs_new_dirent(kernfs_root(parent), name, mode, SYSFS_DIR); - if (!sd) + kn = sysfs_new_dirent(kernfs_root(parent), name, mode, SYSFS_DIR); + if (!kn) return ERR_PTR(-ENOMEM); - sd->s_dir.root = parent->s_dir.root; - sd->s_ns = ns; - sd->priv = priv; + kn->s_dir.root = parent->s_dir.root; + kn->s_ns = ns; + kn->priv = priv; /* link in */ sysfs_addrm_start(&acxt); - rc = sysfs_add_one(&acxt, sd, parent); + rc = sysfs_add_one(&acxt, kn, parent); sysfs_addrm_finish(&acxt); if (!rc) - return sd; + return kn; - kernfs_put(sd); + kernfs_put(kn); return ERR_PTR(rc); } @@ -680,29 +681,28 @@ static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { struct dentry *ret = NULL; - struct dentry *parent = dentry->d_parent; - struct sysfs_dirent *parent_sd = parent->d_fsdata; - struct sysfs_dirent *sd; + struct kernfs_node *parent = dentry->d_parent->d_fsdata; + struct kernfs_node *kn; struct inode *inode; const void *ns = NULL; mutex_lock(&sysfs_mutex); - if (kernfs_ns_enabled(parent_sd)) + if (kernfs_ns_enabled(parent)) ns = sysfs_info(dir->i_sb)->ns; - sd = kernfs_find_ns(parent_sd, dentry->d_name.name, ns); + kn = kernfs_find_ns(parent, dentry->d_name.name, ns); /* no such entry */ - if (!sd) { + if (!kn) { ret = ERR_PTR(-ENOENT); goto out_unlock; } - kernfs_get(sd); - dentry->d_fsdata = sd; + kernfs_get(kn); + dentry->d_fsdata = kn; /* attach dentry and inode */ - inode = sysfs_get_inode(dir->i_sb, sd); + inode = sysfs_get_inode(dir->i_sb, kn); if (!inode) { ret = ERR_PTR(-ENOMEM); goto out_unlock; @@ -726,9 +726,9 @@ const struct inode_operations sysfs_dir_inode_operations = { .listxattr = sysfs_listxattr, }; -static struct sysfs_dirent *sysfs_leftmost_descendant(struct sysfs_dirent *pos) +static struct kernfs_node *sysfs_leftmost_descendant(struct kernfs_node *pos) { - struct sysfs_dirent *last; + struct kernfs_node *last; while (true) { struct rb_node *rbn; @@ -742,7 +742,7 @@ static struct sysfs_dirent *sysfs_leftmost_descendant(struct sysfs_dirent *pos) if (!rbn) break; - pos = to_sysfs_dirent(rbn); + pos = rb_to_kn(rbn); } return last; @@ -751,14 +751,14 @@ static struct sysfs_dirent *sysfs_leftmost_descendant(struct sysfs_dirent *pos) /** * sysfs_next_descendant_post - find the next descendant for post-order walk * @pos: the current position (%NULL to initiate traversal) - * @root: sysfs_dirent whose descendants to walk + * @root: kernfs_node whose descendants to walk * * Find the next descendant to visit for post-order traversal of @root's * descendants. @root is included in the iteration and the last node to be * visited. */ -static struct sysfs_dirent *sysfs_next_descendant_post(struct sysfs_dirent *pos, - struct sysfs_dirent *root) +static struct kernfs_node *sysfs_next_descendant_post(struct kernfs_node *pos, + struct kernfs_node *root) { struct rb_node *rbn; @@ -775,62 +775,62 @@ static struct sysfs_dirent *sysfs_next_descendant_post(struct sysfs_dirent *pos, /* if there's an unvisited sibling, visit its leftmost descendant */ rbn = rb_next(&pos->s_rb); if (rbn) - return sysfs_leftmost_descendant(to_sysfs_dirent(rbn)); + return sysfs_leftmost_descendant(rb_to_kn(rbn)); /* no sibling left, visit parent */ return pos->s_parent; } static void __kernfs_remove(struct sysfs_addrm_cxt *acxt, - struct sysfs_dirent *sd) + struct kernfs_node *kn) { - struct sysfs_dirent *pos, *next; + struct kernfs_node *pos, *next; - if (!sd) + if (!kn) return; - pr_debug("sysfs %s: removing\n", sd->s_name); + pr_debug("sysfs %s: removing\n", kn->s_name); next = NULL; do { pos = next; - next = sysfs_next_descendant_post(pos, sd); + next = sysfs_next_descendant_post(pos, kn); if (pos) sysfs_remove_one(acxt, pos); } while (next); } /** - * kernfs_remove - remove a sysfs_dirent recursively - * @sd: the sysfs_dirent to remove + * kernfs_remove - remove a kernfs_node recursively + * @kn: the kernfs_node to remove * - * Remove @sd along with all its subdirectories and files. + * Remove @kn along with all its subdirectories and files. */ -void kernfs_remove(struct sysfs_dirent *sd) +void kernfs_remove(struct kernfs_node *kn) { struct sysfs_addrm_cxt acxt; sysfs_addrm_start(&acxt); - __kernfs_remove(&acxt, sd); + __kernfs_remove(&acxt, kn); sysfs_addrm_finish(&acxt); } /** - * kernfs_remove_by_name_ns - find a sysfs_dirent by name and remove it - * @dir_sd: parent of the target - * @name: name of the sysfs_dirent to remove - * @ns: namespace tag of the sysfs_dirent to remove + * kernfs_remove_by_name_ns - find a kernfs_node by name and remove it + * @parent: parent of the target + * @name: name of the kernfs_node to remove + * @ns: namespace tag of the kernfs_node to remove * - * Look for the sysfs_dirent with @name and @ns under @dir_sd and remove - * it. Returns 0 on success, -ENOENT if such entry doesn't exist. + * Look for the kernfs_node with @name and @ns under @parent and remove it. + * Returns 0 on success, -ENOENT if such entry doesn't exist. */ -int kernfs_remove_by_name_ns(struct sysfs_dirent *dir_sd, const char *name, +int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, const void *ns) { struct sysfs_addrm_cxt acxt; - struct sysfs_dirent *sd; + struct kernfs_node *kn; - if (!dir_sd) { + if (!parent) { WARN(1, KERN_WARNING "sysfs: can not remove '%s', no directory\n", name); return -ENOENT; @@ -838,13 +838,13 @@ int kernfs_remove_by_name_ns(struct sysfs_dirent *dir_sd, const char *name, sysfs_addrm_start(&acxt); - sd = kernfs_find_ns(dir_sd, name, ns); - if (sd) - __kernfs_remove(&acxt, sd); + kn = kernfs_find_ns(parent, name, ns); + if (kn) + __kernfs_remove(&acxt, kn); sysfs_addrm_finish(&acxt); - if (sd) + if (kn) return 0; else return -ENOENT; @@ -852,12 +852,12 @@ int kernfs_remove_by_name_ns(struct sysfs_dirent *dir_sd, const char *name, /** * kernfs_rename_ns - move and rename a kernfs_node - * @sd: target node + * @kn: target node * @new_parent: new parent to put @sd under * @new_name: new name * @new_ns: new namespace tag */ -int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, +int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, const char *new_name, const void *new_ns) { int error; @@ -865,35 +865,35 @@ int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, mutex_lock(&sysfs_mutex); error = 0; - if ((sd->s_parent == new_parent) && (sd->s_ns == new_ns) && - (strcmp(sd->s_name, new_name) == 0)) + if ((kn->s_parent == new_parent) && (kn->s_ns == new_ns) && + (strcmp(kn->s_name, new_name) == 0)) goto out; /* nothing to rename */ error = -EEXIST; if (kernfs_find_ns(new_parent, new_name, new_ns)) goto out; - /* rename sysfs_dirent */ - if (strcmp(sd->s_name, new_name) != 0) { + /* rename kernfs_node */ + if (strcmp(kn->s_name, new_name) != 0) { error = -ENOMEM; new_name = kstrdup(new_name, GFP_KERNEL); if (!new_name) goto out; - kfree(sd->s_name); - sd->s_name = new_name; + kfree(kn->s_name); + kn->s_name = new_name; } /* * Move to the appropriate place in the appropriate directories rbtree. */ - sysfs_unlink_sibling(sd); + sysfs_unlink_sibling(kn); kernfs_get(new_parent); - kernfs_put(sd->s_parent); - sd->s_ns = new_ns; - sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); - sd->s_parent = new_parent; - sysfs_link_sibling(sd); + kernfs_put(kn->s_parent); + kn->s_ns = new_ns; + kn->s_hash = sysfs_name_hash(kn->s_name, kn->s_ns); + kn->s_parent = new_parent; + sysfs_link_sibling(kn); error = 0; out: @@ -902,9 +902,9 @@ int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, } /* Relationship between s_mode and the DT_xxx types */ -static inline unsigned char dt_type(struct sysfs_dirent *sd) +static inline unsigned char dt_type(struct kernfs_node *kn) { - return (sd->s_mode >> 12) & 15; + return (kn->s_mode >> 12) & 15; } static int sysfs_dir_release(struct inode *inode, struct file *filp) @@ -913,21 +913,21 @@ static int sysfs_dir_release(struct inode *inode, struct file *filp) return 0; } -static struct sysfs_dirent *sysfs_dir_pos(const void *ns, - struct sysfs_dirent *parent_sd, loff_t hash, struct sysfs_dirent *pos) +static struct kernfs_node *sysfs_dir_pos(const void *ns, + struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos) { if (pos) { int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && - pos->s_parent == parent_sd && + pos->s_parent == parent && hash == pos->s_hash; kernfs_put(pos); if (!valid) pos = NULL; } if (!pos && (hash > 1) && (hash < INT_MAX)) { - struct rb_node *node = parent_sd->s_dir.children.rb_node; + struct rb_node *node = parent->s_dir.children.rb_node; while (node) { - pos = to_sysfs_dirent(node); + pos = rb_to_kn(node); if (hash < pos->s_hash) node = node->rb_left; @@ -943,22 +943,22 @@ static struct sysfs_dirent *sysfs_dir_pos(const void *ns, if (!node) pos = NULL; else - pos = to_sysfs_dirent(node); + pos = rb_to_kn(node); } return pos; } -static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns, - struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos) +static struct kernfs_node *sysfs_dir_next_pos(const void *ns, + struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos) { - pos = sysfs_dir_pos(ns, parent_sd, ino, pos); + pos = sysfs_dir_pos(ns, parent, ino, pos); if (pos) do { struct rb_node *node = rb_next(&pos->s_rb); if (!node) pos = NULL; else - pos = to_sysfs_dirent(node); + pos = rb_to_kn(node); } while (pos && pos->s_ns != ns); return pos; } @@ -966,20 +966,20 @@ static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns, static int sysfs_readdir(struct file *file, struct dir_context *ctx) { struct dentry *dentry = file->f_path.dentry; - struct sysfs_dirent *parent_sd = dentry->d_fsdata; - struct sysfs_dirent *pos = file->private_data; + struct kernfs_node *parent = dentry->d_fsdata; + struct kernfs_node *pos = file->private_data; const void *ns = NULL; if (!dir_emit_dots(file, ctx)) return 0; mutex_lock(&sysfs_mutex); - if (kernfs_ns_enabled(parent_sd)) + if (kernfs_ns_enabled(parent)) ns = sysfs_info(dentry->d_sb)->ns; - for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos); + for (pos = sysfs_dir_pos(ns, parent, ctx->pos, pos); pos; - pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) { + pos = sysfs_dir_next_pos(ns, parent, ctx->pos, pos)) { const char *name = pos->s_name; unsigned int type = dt_type(pos); int len = strlen(name); diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index fa053151fa96..1bf07ded826a 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -19,9 +19,9 @@ /* * There's one sysfs_open_file for each open file and one sysfs_open_dirent - * for each sysfs_dirent with one or more open files. + * for each kernfs_node with one or more open files. * - * sysfs_dirent->s_attr.open points to sysfs_open_dirent. s_attr.open is + * kernfs_node->s_attr.open points to sysfs_open_dirent. s_attr.open is * protected by sysfs_open_dirent_lock. * * filp->private_data points to seq_file whose ->private points to @@ -44,14 +44,14 @@ static struct sysfs_open_file *sysfs_of(struct file *file) } /* - * Determine the kernfs_ops for the given sysfs_dirent. This function must + * Determine the kernfs_ops for the given kernfs_node. This function must * be called while holding an active reference. */ -static const struct kernfs_ops *kernfs_ops(struct sysfs_dirent *sd) +static const struct kernfs_ops *kernfs_ops(struct kernfs_node *kn) { - if (sd->s_flags & SYSFS_FLAG_LOCKDEP) - lockdep_assert_held(sd); - return sd->s_attr.ops; + if (kn->s_flags & SYSFS_FLAG_LOCKDEP) + lockdep_assert_held(kn); + return kn->s_attr.ops; } static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) @@ -64,10 +64,10 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) * the ops aren't called concurrently for the same open file. */ mutex_lock(&of->mutex); - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return ERR_PTR(-ENODEV); - ops = kernfs_ops(of->sd); + ops = kernfs_ops(of->kn); if (ops->seq_start) { return ops->seq_start(sf, ppos); } else { @@ -82,7 +82,7 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) { struct sysfs_open_file *of = sf->private; - const struct kernfs_ops *ops = kernfs_ops(of->sd); + const struct kernfs_ops *ops = kernfs_ops(of->kn); if (ops->seq_next) { return ops->seq_next(sf, v, ppos); @@ -99,12 +99,12 @@ static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) static void kernfs_seq_stop(struct seq_file *sf, void *v) { struct sysfs_open_file *of = sf->private; - const struct kernfs_ops *ops = kernfs_ops(of->sd); + const struct kernfs_ops *ops = kernfs_ops(of->kn); if (ops->seq_stop) ops->seq_stop(sf, v); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); mutex_unlock(&of->mutex); } @@ -112,9 +112,9 @@ static int kernfs_seq_show(struct seq_file *sf, void *v) { struct sysfs_open_file *of = sf->private; - of->event = atomic_read(&of->sd->s_attr.open->event); + of->event = atomic_read(&of->kn->s_attr.open->event); - return of->sd->s_attr.ops->seq_show(sf, v); + return of->kn->s_attr.ops->seq_show(sf, v); } static const struct seq_operations kernfs_seq_ops = { @@ -147,19 +147,19 @@ static ssize_t kernfs_file_direct_read(struct sysfs_open_file *of, * the ops aren't called concurrently for the same open file. */ mutex_lock(&of->mutex); - if (!sysfs_get_active(of->sd)) { + if (!sysfs_get_active(of->kn)) { len = -ENODEV; mutex_unlock(&of->mutex); goto out_free; } - ops = kernfs_ops(of->sd); + ops = kernfs_ops(of->kn); if (ops->read) len = ops->read(of, buf, len, *ppos); else len = -EINVAL; - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); mutex_unlock(&of->mutex); if (len < 0) @@ -189,7 +189,7 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, { struct sysfs_open_file *of = sysfs_of(file); - if (of->sd->s_flags & SYSFS_FLAG_HAS_SEQ_SHOW) + if (of->kn->s_flags & SYSFS_FLAG_HAS_SEQ_SHOW) return seq_read(file, user_buf, count, ppos); else return kernfs_file_direct_read(of, user_buf, count, ppos); @@ -234,19 +234,19 @@ static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf, * the ops aren't called concurrently for the same open file. */ mutex_lock(&of->mutex); - if (!sysfs_get_active(of->sd)) { + if (!sysfs_get_active(of->kn)) { mutex_unlock(&of->mutex); len = -ENODEV; goto out_free; } - ops = kernfs_ops(of->sd); + ops = kernfs_ops(of->kn); if (ops->write) len = ops->write(of, buf, len, *ppos); else len = -EINVAL; - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); mutex_unlock(&of->mutex); if (len > 0) @@ -264,13 +264,13 @@ static void kernfs_vma_open(struct vm_area_struct *vma) if (!of->vm_ops) return; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return; if (of->vm_ops->open) of->vm_ops->open(vma); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); } static int kernfs_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) @@ -282,14 +282,14 @@ static int kernfs_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (!of->vm_ops) return VM_FAULT_SIGBUS; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return VM_FAULT_SIGBUS; ret = VM_FAULT_SIGBUS; if (of->vm_ops->fault) ret = of->vm_ops->fault(vma, vmf); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); return ret; } @@ -303,7 +303,7 @@ static int kernfs_vma_page_mkwrite(struct vm_area_struct *vma, if (!of->vm_ops) return VM_FAULT_SIGBUS; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return VM_FAULT_SIGBUS; ret = 0; @@ -312,7 +312,7 @@ static int kernfs_vma_page_mkwrite(struct vm_area_struct *vma, else file_update_time(file); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); return ret; } @@ -326,14 +326,14 @@ static int kernfs_vma_access(struct vm_area_struct *vma, unsigned long addr, if (!of->vm_ops) return -EINVAL; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return -EINVAL; ret = -EINVAL; if (of->vm_ops->access) ret = of->vm_ops->access(vma, addr, buf, len, write); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); return ret; } @@ -348,14 +348,14 @@ static int kernfs_vma_set_policy(struct vm_area_struct *vma, if (!of->vm_ops) return 0; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return -EINVAL; ret = 0; if (of->vm_ops->set_policy) ret = of->vm_ops->set_policy(vma, new); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); return ret; } @@ -369,14 +369,14 @@ static struct mempolicy *kernfs_vma_get_policy(struct vm_area_struct *vma, if (!of->vm_ops) return vma->vm_policy; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return vma->vm_policy; pol = vma->vm_policy; if (of->vm_ops->get_policy) pol = of->vm_ops->get_policy(vma, addr); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); return pol; } @@ -391,14 +391,14 @@ static int kernfs_vma_migrate(struct vm_area_struct *vma, if (!of->vm_ops) return 0; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) return 0; ret = 0; if (of->vm_ops->migrate) ret = of->vm_ops->migrate(vma, from, to, flags); - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); return ret; } #endif @@ -428,16 +428,16 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) * without grabbing @of->mutex by testing HAS_MMAP flag. See the * comment in kernfs_file_open() for more details. */ - if (!(of->sd->s_flags & SYSFS_FLAG_HAS_MMAP)) + if (!(of->kn->s_flags & SYSFS_FLAG_HAS_MMAP)) return -ENODEV; mutex_lock(&of->mutex); rc = -ENODEV; - if (!sysfs_get_active(of->sd)) + if (!sysfs_get_active(of->kn)) goto out_unlock; - ops = kernfs_ops(of->sd); + ops = kernfs_ops(of->kn); rc = ops->mmap(of, vma); /* @@ -465,7 +465,7 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) of->vm_ops = vma->vm_ops; vma->vm_ops = &kernfs_vm_ops; out_put: - sysfs_put_active(of->sd); + sysfs_put_active(of->kn); out_unlock: mutex_unlock(&of->mutex); @@ -474,10 +474,10 @@ out_unlock: /** * sysfs_get_open_dirent - get or create sysfs_open_dirent - * @sd: target sysfs_dirent + * @kn: target kernfs_node * @of: sysfs_open_file for this instance of open * - * If @sd->s_attr.open exists, increment its reference count; + * If @kn->s_attr.open exists, increment its reference count; * otherwise, create one. @of is chained to the files list. * * LOCKING: @@ -486,7 +486,7 @@ out_unlock: * RETURNS: * 0 on success, -errno on failure. */ -static int sysfs_get_open_dirent(struct sysfs_dirent *sd, +static int sysfs_get_open_dirent(struct kernfs_node *kn, struct sysfs_open_file *of) { struct sysfs_open_dirent *od, *new_od = NULL; @@ -495,12 +495,12 @@ static int sysfs_get_open_dirent(struct sysfs_dirent *sd, mutex_lock(&sysfs_open_file_mutex); spin_lock_irq(&sysfs_open_dirent_lock); - if (!sd->s_attr.open && new_od) { - sd->s_attr.open = new_od; + if (!kn->s_attr.open && new_od) { + kn->s_attr.open = new_od; new_od = NULL; } - od = sd->s_attr.open; + od = kn->s_attr.open; if (od) { atomic_inc(&od->refcnt); list_add_tail(&of->list, &od->files); @@ -528,19 +528,19 @@ static int sysfs_get_open_dirent(struct sysfs_dirent *sd, /** * sysfs_put_open_dirent - put sysfs_open_dirent - * @sd: target sysfs_dirent + * @kn: target kernfs_nodet * @of: associated sysfs_open_file * - * Put @sd->s_attr.open and unlink @of from the files list. If + * Put @kn->s_attr.open and unlink @of from the files list. If * reference count reaches zero, disassociate and free it. * * LOCKING: * None. */ -static void sysfs_put_open_dirent(struct sysfs_dirent *sd, +static void sysfs_put_open_dirent(struct kernfs_node *kn, struct sysfs_open_file *of) { - struct sysfs_open_dirent *od = sd->s_attr.open; + struct sysfs_open_dirent *od = kn->s_attr.open; unsigned long flags; mutex_lock(&sysfs_open_file_mutex); @@ -550,7 +550,7 @@ static void sysfs_put_open_dirent(struct sysfs_dirent *sd, list_del(&of->list); if (atomic_dec_and_test(&od->refcnt)) - sd->s_attr.open = NULL; + kn->s_attr.open = NULL; else od = NULL; @@ -562,16 +562,16 @@ static void sysfs_put_open_dirent(struct sysfs_dirent *sd, static int kernfs_file_open(struct inode *inode, struct file *file) { - struct sysfs_dirent *attr_sd = file->f_path.dentry->d_fsdata; + struct kernfs_node *kn = file->f_path.dentry->d_fsdata; const struct kernfs_ops *ops; struct sysfs_open_file *of; bool has_read, has_write, has_mmap; int error = -EACCES; - if (!sysfs_get_active(attr_sd)) + if (!sysfs_get_active(kn)) return -ENODEV; - ops = kernfs_ops(attr_sd); + ops = kernfs_ops(kn); has_read = ops->seq_show || ops->read || ops->mmap; has_write = ops->write || ops->mmap; @@ -612,7 +612,7 @@ static int kernfs_file_open(struct inode *inode, struct file *file) else mutex_init(&of->mutex); - of->sd = attr_sd; + of->kn = kn; of->file = file; /* @@ -634,12 +634,12 @@ static int kernfs_file_open(struct inode *inode, struct file *file) file->f_mode |= FMODE_PWRITE; /* make sure we have open dirent struct */ - error = sysfs_get_open_dirent(attr_sd, of); + error = sysfs_get_open_dirent(kn, of); if (error) goto err_close; /* open succeeded, put active references */ - sysfs_put_active(attr_sd); + sysfs_put_active(kn); return 0; err_close: @@ -647,32 +647,32 @@ err_close: err_free: kfree(of); err_out: - sysfs_put_active(attr_sd); + sysfs_put_active(kn); return error; } static int kernfs_file_release(struct inode *inode, struct file *filp) { - struct sysfs_dirent *sd = filp->f_path.dentry->d_fsdata; + struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; struct sysfs_open_file *of = sysfs_of(filp); - sysfs_put_open_dirent(sd, of); + sysfs_put_open_dirent(kn, of); seq_release(inode, filp); kfree(of); return 0; } -void sysfs_unmap_bin_file(struct sysfs_dirent *sd) +void sysfs_unmap_bin_file(struct kernfs_node *kn) { struct sysfs_open_dirent *od; struct sysfs_open_file *of; - if (!(sd->s_flags & SYSFS_FLAG_HAS_MMAP)) + if (!(kn->s_flags & SYSFS_FLAG_HAS_MMAP)) return; spin_lock_irq(&sysfs_open_dirent_lock); - od = sd->s_attr.open; + od = kn->s_attr.open; if (od) atomic_inc(&od->refcnt); spin_unlock_irq(&sysfs_open_dirent_lock); @@ -686,7 +686,7 @@ void sysfs_unmap_bin_file(struct sysfs_dirent *sd) } mutex_unlock(&sysfs_open_file_mutex); - sysfs_put_open_dirent(sd, NULL); + sysfs_put_open_dirent(kn, NULL); } /* Sysfs attribute files are pollable. The idea is that you read @@ -705,16 +705,16 @@ void sysfs_unmap_bin_file(struct sysfs_dirent *sd) static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) { struct sysfs_open_file *of = sysfs_of(filp); - struct sysfs_dirent *attr_sd = filp->f_path.dentry->d_fsdata; - struct sysfs_open_dirent *od = attr_sd->s_attr.open; + struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; + struct sysfs_open_dirent *od = kn->s_attr.open; /* need parent for the kobj, grab both */ - if (!sysfs_get_active(attr_sd)) + if (!sysfs_get_active(kn)) goto trigger; poll_wait(filp, &od->poll, wait); - sysfs_put_active(attr_sd); + sysfs_put_active(kn); if (of->event != atomic_read(&od->event)) goto trigger; @@ -727,19 +727,19 @@ static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) /** * kernfs_notify - notify a kernfs file - * @sd: file to notify + * @kn: file to notify * - * Notify @sd such that poll(2) on @sd wakes up. + * Notify @kn such that poll(2) on @kn wakes up. */ -void kernfs_notify(struct sysfs_dirent *sd) +void kernfs_notify(struct kernfs_node *kn) { struct sysfs_open_dirent *od; unsigned long flags; spin_lock_irqsave(&sysfs_open_dirent_lock, flags); - if (!WARN_ON(sysfs_type(sd) != SYSFS_KOBJ_ATTR)) { - od = sd->s_attr.open; + if (!WARN_ON(sysfs_type(kn) != SYSFS_KOBJ_ATTR)) { + od = kn->s_attr.open; if (od) { atomic_inc(&od->event); wake_up_interruptible(&od->poll); @@ -773,51 +773,51 @@ const struct file_operations kernfs_file_operations = { * * Returns the created node on success, ERR_PTR() value on error. */ -struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *parent, - const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, - void *priv, const void *ns, - struct lock_class_key *key) +struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns, + struct lock_class_key *key) { struct sysfs_addrm_cxt acxt; - struct sysfs_dirent *sd; + struct kernfs_node *kn; int rc; - sd = sysfs_new_dirent(kernfs_root(parent), name, + kn = sysfs_new_dirent(kernfs_root(parent), name, (mode & S_IALLUGO) | S_IFREG, SYSFS_KOBJ_ATTR); - if (!sd) + if (!kn) return ERR_PTR(-ENOMEM); - sd->s_attr.ops = ops; - sd->s_attr.size = size; - sd->s_ns = ns; - sd->priv = priv; + kn->s_attr.ops = ops; + kn->s_attr.size = size; + kn->s_ns = ns; + kn->priv = priv; #ifdef CONFIG_DEBUG_LOCK_ALLOC if (key) { - lockdep_init_map(&sd->dep_map, "s_active", key, 0); - sd->s_flags |= SYSFS_FLAG_LOCKDEP; + lockdep_init_map(&kn->dep_map, "s_active", key, 0); + kn->s_flags |= SYSFS_FLAG_LOCKDEP; } #endif /* - * sd->s_attr.ops is accesible only while holding active ref. We + * kn->s_attr.ops is accesible only while holding active ref. We * need to know whether some ops are implemented outside active * ref. Cache their existence in flags. */ if (ops->seq_show) - sd->s_flags |= SYSFS_FLAG_HAS_SEQ_SHOW; + kn->s_flags |= SYSFS_FLAG_HAS_SEQ_SHOW; if (ops->mmap) - sd->s_flags |= SYSFS_FLAG_HAS_MMAP; + kn->s_flags |= SYSFS_FLAG_HAS_MMAP; sysfs_addrm_start(&acxt); - rc = sysfs_add_one(&acxt, sd, parent); + rc = sysfs_add_one(&acxt, kn, parent); sysfs_addrm_finish(&acxt); if (rc) { - kernfs_put(sd); + kernfs_put(kn); return ERR_PTR(rc); } - return sd; + return kn; } diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index 18ad431e8c2a..9e74eed63539 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -46,36 +46,36 @@ void __init sysfs_inode_init(void) panic("failed to init sysfs_backing_dev_info"); } -static struct sysfs_inode_attrs *sysfs_inode_attrs(struct sysfs_dirent *sd) +static struct sysfs_inode_attrs *sysfs_inode_attrs(struct kernfs_node *kn) { struct iattr *iattrs; - if (sd->s_iattr) - return sd->s_iattr; + if (kn->s_iattr) + return kn->s_iattr; - sd->s_iattr = kzalloc(sizeof(struct sysfs_inode_attrs), GFP_KERNEL); - if (!sd->s_iattr) + kn->s_iattr = kzalloc(sizeof(struct sysfs_inode_attrs), GFP_KERNEL); + if (!kn->s_iattr) return NULL; - iattrs = &sd->s_iattr->ia_iattr; + iattrs = &kn->s_iattr->ia_iattr; /* assign default attributes */ - iattrs->ia_mode = sd->s_mode; + iattrs->ia_mode = kn->s_mode; iattrs->ia_uid = GLOBAL_ROOT_UID; iattrs->ia_gid = GLOBAL_ROOT_GID; iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; - simple_xattrs_init(&sd->s_iattr->xattrs); + simple_xattrs_init(&kn->s_iattr->xattrs); - return sd->s_iattr; + return kn->s_iattr; } -static int __kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr) +static int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) { struct sysfs_inode_attrs *attrs; struct iattr *iattrs; unsigned int ia_valid = iattr->ia_valid; - attrs = sysfs_inode_attrs(sd); + attrs = sysfs_inode_attrs(kn); if (!attrs) return -ENOMEM; @@ -93,24 +93,24 @@ static int __kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr) iattrs->ia_ctime = iattr->ia_ctime; if (ia_valid & ATTR_MODE) { umode_t mode = iattr->ia_mode; - iattrs->ia_mode = sd->s_mode = mode; + iattrs->ia_mode = kn->s_mode = mode; } return 0; } /** * kernfs_setattr - set iattr on a node - * @sd: target node + * @kn: target node * @iattr: iattr to set * * Returns 0 on success, -errno on failure. */ -int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr) +int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) { int ret; mutex_lock(&sysfs_mutex); - ret = __kernfs_setattr(sd, iattr); + ret = __kernfs_setattr(kn, iattr); mutex_unlock(&sysfs_mutex); return ret; } @@ -118,10 +118,10 @@ int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr) int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) { struct inode *inode = dentry->d_inode; - struct sysfs_dirent *sd = dentry->d_fsdata; + struct kernfs_node *kn = dentry->d_fsdata; int error; - if (!sd) + if (!kn) return -EINVAL; mutex_lock(&sysfs_mutex); @@ -129,7 +129,7 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) if (error) goto out; - error = __kernfs_setattr(sd, iattr); + error = __kernfs_setattr(kn, iattr); if (error) goto out; @@ -141,14 +141,14 @@ out: return error; } -static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, +static int sysfs_sd_setsecdata(struct kernfs_node *kn, void **secdata, u32 *secdata_len) { struct sysfs_inode_attrs *attrs; void *old_secdata; size_t old_secdata_len; - attrs = sysfs_inode_attrs(sd); + attrs = sysfs_inode_attrs(kn); if (!attrs) return -ENOMEM; @@ -166,13 +166,13 @@ static int sysfs_sd_setsecdata(struct sysfs_dirent *sd, void **secdata, int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { - struct sysfs_dirent *sd = dentry->d_fsdata; + struct kernfs_node *kn = dentry->d_fsdata; struct sysfs_inode_attrs *attrs; void *secdata; int error; u32 secdata_len = 0; - attrs = sysfs_inode_attrs(sd); + attrs = sysfs_inode_attrs(kn); if (!attrs) return -ENOMEM; @@ -188,7 +188,7 @@ int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, return error; mutex_lock(&sysfs_mutex); - error = sysfs_sd_setsecdata(sd, &secdata, &secdata_len); + error = sysfs_sd_setsecdata(kn, &secdata, &secdata_len); mutex_unlock(&sysfs_mutex); if (secdata) @@ -204,10 +204,10 @@ int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, int sysfs_removexattr(struct dentry *dentry, const char *name) { - struct sysfs_dirent *sd = dentry->d_fsdata; + struct kernfs_node *kn = dentry->d_fsdata; struct sysfs_inode_attrs *attrs; - attrs = sysfs_inode_attrs(sd); + attrs = sysfs_inode_attrs(kn); if (!attrs) return -ENOMEM; @@ -217,10 +217,10 @@ int sysfs_removexattr(struct dentry *dentry, const char *name) ssize_t sysfs_getxattr(struct dentry *dentry, const char *name, void *buf, size_t size) { - struct sysfs_dirent *sd = dentry->d_fsdata; + struct kernfs_node *kn = dentry->d_fsdata; struct sysfs_inode_attrs *attrs; - attrs = sysfs_inode_attrs(sd); + attrs = sysfs_inode_attrs(kn); if (!attrs) return -ENOMEM; @@ -229,10 +229,10 @@ ssize_t sysfs_getxattr(struct dentry *dentry, const char *name, void *buf, ssize_t sysfs_listxattr(struct dentry *dentry, char *buf, size_t size) { - struct sysfs_dirent *sd = dentry->d_fsdata; + struct kernfs_node *kn = dentry->d_fsdata; struct sysfs_inode_attrs *attrs; - attrs = sysfs_inode_attrs(sd); + attrs = sysfs_inode_attrs(kn); if (!attrs) return -ENOMEM; @@ -254,57 +254,58 @@ static inline void set_inode_attr(struct inode *inode, struct iattr *iattr) inode->i_ctime = iattr->ia_ctime; } -static void sysfs_refresh_inode(struct sysfs_dirent *sd, struct inode *inode) +static void sysfs_refresh_inode(struct kernfs_node *kn, struct inode *inode) { - struct sysfs_inode_attrs *attrs = sd->s_iattr; + struct sysfs_inode_attrs *attrs = kn->s_iattr; - inode->i_mode = sd->s_mode; + inode->i_mode = kn->s_mode; if (attrs) { - /* sysfs_dirent has non-default attributes - * get them from persistent copy in sysfs_dirent + /* + * kernfs_node has non-default attributes get them from + * persistent copy in kernfs_node. */ set_inode_attr(inode, &attrs->ia_iattr); security_inode_notifysecctx(inode, attrs->ia_secdata, attrs->ia_secdata_len); } - if (sysfs_type(sd) == SYSFS_DIR) - set_nlink(inode, sd->s_dir.subdirs + 2); + if (sysfs_type(kn) == SYSFS_DIR) + set_nlink(inode, kn->s_dir.subdirs + 2); } int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { - struct sysfs_dirent *sd = dentry->d_fsdata; + struct kernfs_node *kn = dentry->d_fsdata; struct inode *inode = dentry->d_inode; mutex_lock(&sysfs_mutex); - sysfs_refresh_inode(sd, inode); + sysfs_refresh_inode(kn, inode); mutex_unlock(&sysfs_mutex); generic_fillattr(inode, stat); return 0; } -static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) +static void sysfs_init_inode(struct kernfs_node *kn, struct inode *inode) { - kernfs_get(sd); - inode->i_private = sd; + kernfs_get(kn); + inode->i_private = kn; inode->i_mapping->a_ops = &sysfs_aops; inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; inode->i_op = &sysfs_inode_operations; - set_default_inode_attr(inode, sd->s_mode); - sysfs_refresh_inode(sd, inode); + set_default_inode_attr(inode, kn->s_mode); + sysfs_refresh_inode(kn, inode); /* initialize inode according to type */ - switch (sysfs_type(sd)) { + switch (sysfs_type(kn)) { case SYSFS_DIR: inode->i_op = &sysfs_dir_inode_operations; inode->i_fop = &sysfs_dir_operations; break; case SYSFS_KOBJ_ATTR: - inode->i_size = sd->s_attr.size; + inode->i_size = kn->s_attr.size; inode->i_fop = &kernfs_file_operations; break; case SYSFS_KOBJ_LINK: @@ -318,13 +319,13 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) } /** - * sysfs_get_inode - get inode for sysfs_dirent + * sysfs_get_inode - get inode for kernfs_node * @sb: super block - * @sd: sysfs_dirent to allocate inode for + * @kn: kernfs_node to allocate inode for * - * Get inode for @sd. If such inode doesn't exist, a new inode - * is allocated and basics are initialized. New inode is - * returned locked. + * Get inode for @kn. If such inode doesn't exist, a new inode is + * allocated and basics are initialized. New inode is returned + * locked. * * LOCKING: * Kernel thread context (may sleep). @@ -332,44 +333,44 @@ static void sysfs_init_inode(struct sysfs_dirent *sd, struct inode *inode) * RETURNS: * Pointer to allocated inode on success, NULL on failure. */ -struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd) +struct inode *sysfs_get_inode(struct super_block *sb, struct kernfs_node *kn) { struct inode *inode; - inode = iget_locked(sb, sd->s_ino); + inode = iget_locked(sb, kn->s_ino); if (inode && (inode->i_state & I_NEW)) - sysfs_init_inode(sd, inode); + sysfs_init_inode(kn, inode); return inode; } /* - * The sysfs_dirent serves as both an inode and a directory entry for sysfs. - * To prevent the sysfs inode numbers from being freed prematurely we take a - * reference to sysfs_dirent from the sysfs inode. A + * The kernfs_node serves as both an inode and a directory entry for sysfs. + * To prevent the sysfs inode numbers from being freed prematurely we take + * a reference to kernfs_node from the sysfs inode. A * super_operations.evict_inode() implementation is needed to drop that * reference upon inode destruction. */ void sysfs_evict_inode(struct inode *inode) { - struct sysfs_dirent *sd = inode->i_private; + struct kernfs_node *kn = inode->i_private; truncate_inode_pages(&inode->i_data, 0); clear_inode(inode); - kernfs_put(sd); + kernfs_put(kn); } int sysfs_permission(struct inode *inode, int mask) { - struct sysfs_dirent *sd; + struct kernfs_node *kn; if (mask & MAY_NOT_BLOCK) return -ECHILD; - sd = inode->i_private; + kn = inode->i_private; mutex_lock(&sysfs_mutex); - sysfs_refresh_inode(sd, inode); + sysfs_refresh_inode(kn, inode); mutex_unlock(&sysfs_mutex); return generic_permission(inode, mask); diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 910e485b7333..b7ea76c6fb33 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -31,24 +31,24 @@ struct sysfs_inode_attrs { /* SYSFS_TYPE_MASK and types are defined in include/linux/kernfs.h */ /** - * kernfs_root - find out the kernfs_root a sysfs_dirent belongs to - * @sd: sysfs_dirent of interest + * kernfs_root - find out the kernfs_root a kernfs_node belongs to + * @kn: kernfs_node of interest * - * Return the kernfs_root @sd belongs to. + * Return the kernfs_root @kn belongs to. */ -static inline struct kernfs_root *kernfs_root(struct sysfs_dirent *sd) +static inline struct kernfs_root *kernfs_root(struct kernfs_node *kn) { /* if parent exists, it's always a dir; otherwise, @sd is a dir */ - if (sd->s_parent) - sd = sd->s_parent; - return sd->s_dir.root; + if (kn->s_parent) + kn = kn->s_parent; + return kn->s_dir.root; } /* * Context structure to be used while adding/removing nodes. */ struct sysfs_addrm_cxt { - struct sysfs_dirent *removed; + struct kernfs_node *removed; }; /* @@ -62,10 +62,10 @@ struct sysfs_super_info { struct kernfs_root *root; /* - * Each sb is associated with one namespace tag, currently the network - * namespace of the task which mounted this sysfs instance. If multiple - * tags become necessary, make the following an array and compare - * sysfs_dirent tag against every entry. + * Each sb is associated with one namespace tag, currently the + * network namespace of the task which mounted this sysfs instance. + * If multiple tags become necessary, make the following an array + * and compare kernfs_node tag against every entry. */ const void *ns; }; @@ -76,7 +76,7 @@ extern struct kmem_cache *sysfs_dir_cachep; /* * inode.c */ -struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd); +struct inode *sysfs_get_inode(struct super_block *sb, struct kernfs_node *kn); void sysfs_evict_inode(struct inode *inode); int sysfs_permission(struct inode *inode, int mask); int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); @@ -98,21 +98,21 @@ extern const struct dentry_operations sysfs_dentry_ops; extern const struct file_operations sysfs_dir_operations; extern const struct inode_operations sysfs_dir_inode_operations; -struct sysfs_dirent *sysfs_get_active(struct sysfs_dirent *sd); -void sysfs_put_active(struct sysfs_dirent *sd); +struct kernfs_node *sysfs_get_active(struct kernfs_node *kn); +void sysfs_put_active(struct kernfs_node *kn); void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt); -int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, - struct sysfs_dirent *parent_sd); +int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct kernfs_node *kn, + struct kernfs_node *parent); void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); -struct sysfs_dirent *sysfs_new_dirent(struct kernfs_root *root, - const char *name, umode_t mode, int type); +struct kernfs_node *sysfs_new_dirent(struct kernfs_root *root, + const char *name, umode_t mode, int type); /* * file.c */ extern const struct file_operations kernfs_file_operations; -void sysfs_unmap_bin_file(struct sysfs_dirent *sd); +void sysfs_unmap_bin_file(struct kernfs_node *kn); /* * symlink.c diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 84c83e24bf25..9dbbf37b1af9 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -39,7 +39,7 @@ static int sysfs_fill_super(struct super_block *sb) /* get root inode, initialize and unlock it */ mutex_lock(&sysfs_mutex); - inode = sysfs_get_inode(sb, info->root->sd); + inode = sysfs_get_inode(sb, info->root->kn); mutex_unlock(&sysfs_mutex); if (!inode) { pr_debug("sysfs: could not get root inode\n"); @@ -52,8 +52,8 @@ static int sysfs_fill_super(struct super_block *sb) pr_debug("%s: could not get root dentry!\n", __func__); return -ENOMEM; } - kernfs_get(info->root->sd); - root->d_fsdata = info->root->sd; + kernfs_get(info->root->kn); + root->d_fsdata = info->root->kn; sb->s_root = root; sb->s_d_op = &sysfs_dentry_ops; return 0; @@ -145,7 +145,7 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, void kernfs_kill_sb(struct super_block *sb) { struct sysfs_super_info *info = sysfs_info(sb); - struct sysfs_dirent *root_sd = sb->s_root->d_fsdata; + struct kernfs_node *root_kn = sb->s_root->d_fsdata; /* * Remove the superblock from fs_supers/s_instances @@ -153,13 +153,13 @@ void kernfs_kill_sb(struct super_block *sb) */ kill_anon_super(sb); kfree(info); - kernfs_put(root_sd); + kernfs_put(root_kn); } void __init kernfs_init(void) { sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache", - sizeof(struct sysfs_dirent), + sizeof(struct kernfs_node), 0, SLAB_PANIC, NULL); sysfs_inode_init(); } diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index adf28755b0ee..29dcf5e8debd 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -22,50 +22,50 @@ * * Returns the created node on success, ERR_PTR() value on error. */ -struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, - const char *name, - struct sysfs_dirent *target) +struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, + const char *name, + struct kernfs_node *target) { - struct sysfs_dirent *sd; + struct kernfs_node *kn; struct sysfs_addrm_cxt acxt; int error; - sd = sysfs_new_dirent(kernfs_root(parent), name, S_IFLNK|S_IRWXUGO, + kn = sysfs_new_dirent(kernfs_root(parent), name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK); - if (!sd) + if (!kn) return ERR_PTR(-ENOMEM); if (kernfs_ns_enabled(parent)) - sd->s_ns = target->s_ns; - sd->s_symlink.target_sd = target; + kn->s_ns = target->s_ns; + kn->s_symlink.target_kn = target; kernfs_get(target); /* ref owned by symlink */ sysfs_addrm_start(&acxt); - error = sysfs_add_one(&acxt, sd, parent); + error = sysfs_add_one(&acxt, kn, parent); sysfs_addrm_finish(&acxt); if (!error) - return sd; + return kn; - kernfs_put(sd); + kernfs_put(kn); return ERR_PTR(error); } -static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, - struct sysfs_dirent *target_sd, char *path) +static int sysfs_get_target_path(struct kernfs_node *parent, + struct kernfs_node *target, char *path) { - struct sysfs_dirent *base, *sd; + struct kernfs_node *base, *kn; char *s = path; int len = 0; /* go up to the root, stop at the base */ - base = parent_sd; + base = parent; while (base->s_parent) { - sd = target_sd->s_parent; - while (sd->s_parent && base != sd) - sd = sd->s_parent; + kn = target->s_parent; + while (kn->s_parent && base != kn) + kn = kn->s_parent; - if (base == sd) + if (base == kn) break; strcpy(s, "../"); @@ -74,10 +74,10 @@ static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, } /* determine end of target string for reverse fillup */ - sd = target_sd; - while (sd->s_parent && sd != base) { - len += strlen(sd->s_name) + 1; - sd = sd->s_parent; + kn = target; + while (kn->s_parent && kn != base) { + len += strlen(kn->s_name) + 1; + kn = kn->s_parent; } /* check limits */ @@ -88,16 +88,16 @@ static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, return -ENAMETOOLONG; /* reverse fillup of target string from target to base */ - sd = target_sd; - while (sd->s_parent && sd != base) { - int slen = strlen(sd->s_name); + kn = target; + while (kn->s_parent && kn != base) { + int slen = strlen(kn->s_name); len -= slen; - strncpy(s + len, sd->s_name, slen); + strncpy(s + len, kn->s_name, slen); if (len) s[--len] = '/'; - sd = sd->s_parent; + kn = kn->s_parent; } return 0; @@ -105,13 +105,13 @@ static int sysfs_get_target_path(struct sysfs_dirent *parent_sd, static int sysfs_getlink(struct dentry *dentry, char *path) { - struct sysfs_dirent *sd = dentry->d_fsdata; - struct sysfs_dirent *parent_sd = sd->s_parent; - struct sysfs_dirent *target_sd = sd->s_symlink.target_sd; + struct kernfs_node *kn = dentry->d_fsdata; + struct kernfs_node *parent = kn->s_parent; + struct kernfs_node *target = kn->s_symlink.target_kn; int error; mutex_lock(&sysfs_mutex); - error = sysfs_get_target_path(parent_sd, target_sd, path); + error = sysfs_get_target_path(parent, target, path); mutex_unlock(&sysfs_mutex); return error; diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 2fea501889e7..f1efe3df0de6 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -21,23 +21,23 @@ DEFINE_SPINLOCK(sysfs_symlink_target_lock); /** * sysfs_pathname - return full path to sysfs dirent - * @sd: sysfs_dirent whose path we want + * @kn: kernfs_node whose path we want * @path: caller allocated buffer of size PATH_MAX * * Gives the name "/" to the sysfs_root entry; any path returned * is relative to wherever sysfs is mounted. */ -static char *sysfs_pathname(struct sysfs_dirent *sd, char *path) +static char *sysfs_pathname(struct kernfs_node *kn, char *path) { - if (sd->s_parent) { - sysfs_pathname(sd->s_parent, path); + if (kn->s_parent) { + sysfs_pathname(kn->s_parent, path); strlcat(path, "/", PATH_MAX); } - strlcat(path, sd->s_name, PATH_MAX); + strlcat(path, kn->s_name, PATH_MAX); return path; } -void sysfs_warn_dup(struct sysfs_dirent *parent, const char *name) +void sysfs_warn_dup(struct kernfs_node *parent, const char *name) { char *path; @@ -61,26 +61,26 @@ void sysfs_warn_dup(struct sysfs_dirent *parent, const char *name) */ int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) { - struct sysfs_dirent *parent_sd, *sd; + struct kernfs_node *parent, *kn; BUG_ON(!kobj); if (kobj->parent) - parent_sd = kobj->parent->sd; + parent = kobj->parent->sd; else - parent_sd = sysfs_root_sd; + parent = sysfs_root_kn; - if (!parent_sd) + if (!parent) return -ENOENT; - sd = kernfs_create_dir_ns(parent_sd, kobject_name(kobj), kobj, ns); - if (IS_ERR(sd)) { - if (PTR_ERR(sd) == -EEXIST) - sysfs_warn_dup(parent_sd, kobject_name(kobj)); - return PTR_ERR(sd); + kn = kernfs_create_dir_ns(parent, kobject_name(kobj), kobj, ns); + if (IS_ERR(kn)) { + if (PTR_ERR(kn) == -EEXIST) + sysfs_warn_dup(parent, kobject_name(kobj)); + return PTR_ERR(kn); } - kobj->sd = sd; + kobj->sd = kn; return 0; } @@ -94,47 +94,47 @@ int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) */ void sysfs_remove_dir(struct kobject *kobj) { - struct sysfs_dirent *sd = kobj->sd; + struct kernfs_node *kn = kobj->sd; /* * In general, kboject owner is responsible for ensuring removal * doesn't race with other operations and sysfs doesn't provide any * protection; however, when @kobj is used as a symlink target, the * symlinking entity usually doesn't own @kobj and thus has no - * control over removal. @kobj->sd may be removed anytime and - * symlink code may end up dereferencing an already freed sd. + * control over removal. @kobj->sd may be removed anytime + * and symlink code may end up dereferencing an already freed node. * - * sysfs_symlink_target_lock synchronizes @kobj->sd disassociation - * against symlink operations so that symlink code can safely - * dereference @kobj->sd. + * sysfs_symlink_target_lock synchronizes @kobj->sd + * disassociation against symlink operations so that symlink code + * can safely dereference @kobj->sd. */ spin_lock(&sysfs_symlink_target_lock); kobj->sd = NULL; spin_unlock(&sysfs_symlink_target_lock); - if (sd) { - WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); - kernfs_remove(sd); + if (kn) { + WARN_ON_ONCE(sysfs_type(kn) != SYSFS_DIR); + kernfs_remove(kn); } } int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, const void *new_ns) { - struct sysfs_dirent *parent_sd = kobj->sd->s_parent; + struct kernfs_node *parent = kobj->sd->s_parent; - return kernfs_rename_ns(kobj->sd, parent_sd, new_name, new_ns); + return kernfs_rename_ns(kobj->sd, parent, new_name, new_ns); } int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, const void *new_ns) { - struct sysfs_dirent *sd = kobj->sd; - struct sysfs_dirent *new_parent_sd; + struct kernfs_node *kn = kobj->sd; + struct kernfs_node *new_parent; - BUG_ON(!sd->s_parent); - new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? - new_parent_kobj->sd : sysfs_root_sd; + BUG_ON(!kn->s_parent); + new_parent = new_parent_kobj && new_parent_kobj->sd ? + new_parent_kobj->sd : sysfs_root_kn; - return kernfs_rename_ns(sd, new_parent_sd, sd->s_name, new_ns); + return kernfs_rename_ns(kn, new_parent, kn->s_name, new_ns); } diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index a67d1c682fed..be1cc39035bd 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -22,15 +22,15 @@ #include "../kernfs/kernfs-internal.h" /* - * Determine ktype->sysfs_ops for the given sysfs_dirent. This function + * Determine ktype->sysfs_ops for the given kernfs_node. This function * must be called while holding an active reference. */ -static const struct sysfs_ops *sysfs_file_ops(struct sysfs_dirent *sd) +static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn) { - struct kobject *kobj = sd->s_parent->priv; + struct kobject *kobj = kn->s_parent->priv; - if (sd->s_flags & SYSFS_FLAG_LOCKDEP) - lockdep_assert_held(sd); + if (kn->s_flags & SYSFS_FLAG_LOCKDEP) + lockdep_assert_held(kn); return kobj->ktype ? kobj->ktype->sysfs_ops : NULL; } @@ -42,8 +42,8 @@ static const struct sysfs_ops *sysfs_file_ops(struct sysfs_dirent *sd) static int sysfs_kf_seq_show(struct seq_file *sf, void *v) { struct sysfs_open_file *of = sf->private; - struct kobject *kobj = of->sd->s_parent->priv; - const struct sysfs_ops *ops = sysfs_file_ops(of->sd); + struct kobject *kobj = of->kn->s_parent->priv; + const struct sysfs_ops *ops = sysfs_file_ops(of->kn); ssize_t count; char *buf; @@ -59,7 +59,7 @@ static int sysfs_kf_seq_show(struct seq_file *sf, void *v) * if @ops->show() isn't implemented. */ if (ops->show) { - count = ops->show(kobj, of->sd->priv, buf); + count = ops->show(kobj, of->kn->priv, buf); if (count < 0) return count; } @@ -81,8 +81,8 @@ static int sysfs_kf_seq_show(struct seq_file *sf, void *v) static ssize_t sysfs_kf_bin_read(struct sysfs_open_file *of, char *buf, size_t count, loff_t pos) { - struct bin_attribute *battr = of->sd->priv; - struct kobject *kobj = of->sd->s_parent->priv; + struct bin_attribute *battr = of->kn->priv; + struct kobject *kobj = of->kn->s_parent->priv; loff_t size = file_inode(of->file)->i_size; if (!count) @@ -105,21 +105,21 @@ static ssize_t sysfs_kf_bin_read(struct sysfs_open_file *of, char *buf, static ssize_t sysfs_kf_write(struct sysfs_open_file *of, char *buf, size_t count, loff_t pos) { - const struct sysfs_ops *ops = sysfs_file_ops(of->sd); - struct kobject *kobj = of->sd->s_parent->priv; + const struct sysfs_ops *ops = sysfs_file_ops(of->kn); + struct kobject *kobj = of->kn->s_parent->priv; if (!count) return 0; - return ops->store(kobj, of->sd->priv, buf, count); + return ops->store(kobj, of->kn->priv, buf, count); } /* kernfs write callback for bin sysfs files */ static ssize_t sysfs_kf_bin_write(struct sysfs_open_file *of, char *buf, size_t count, loff_t pos) { - struct bin_attribute *battr = of->sd->priv; - struct kobject *kobj = of->sd->s_parent->priv; + struct bin_attribute *battr = of->kn->priv; + struct kobject *kobj = of->kn->s_parent->priv; loff_t size = file_inode(of->file)->i_size; if (size) { @@ -139,30 +139,30 @@ static ssize_t sysfs_kf_bin_write(struct sysfs_open_file *of, char *buf, static int sysfs_kf_bin_mmap(struct sysfs_open_file *of, struct vm_area_struct *vma) { - struct bin_attribute *battr = of->sd->priv; - struct kobject *kobj = of->sd->s_parent->priv; + struct bin_attribute *battr = of->kn->priv; + struct kobject *kobj = of->kn->s_parent->priv; return battr->mmap(of->file, kobj, battr, vma); } -void sysfs_notify(struct kobject *k, const char *dir, const char *attr) +void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr) { - struct sysfs_dirent *sd = k->sd, *tmp; + struct kernfs_node *kn = kobj->sd, *tmp; - if (sd && dir) - sd = kernfs_find_and_get(sd, dir); + if (kn && dir) + kn = kernfs_find_and_get(kn, dir); else - kernfs_get(sd); + kernfs_get(kn); - if (sd && attr) { - tmp = kernfs_find_and_get(sd, attr); - kernfs_put(sd); - sd = tmp; + if (kn && attr) { + tmp = kernfs_find_and_get(kn, attr); + kernfs_put(kn); + kn = tmp; } - if (sd) { - kernfs_notify(sd); - kernfs_put(sd); + if (kn) { + kernfs_notify(kn); + kernfs_put(kn); } } EXPORT_SYMBOL_GPL(sysfs_notify); @@ -202,17 +202,17 @@ static const struct kernfs_ops sysfs_bin_kfops_mmap = { .mmap = sysfs_kf_bin_mmap, }; -int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, +int sysfs_add_file_mode_ns(struct kernfs_node *parent, const struct attribute *attr, bool is_bin, umode_t mode, const void *ns) { struct lock_class_key *key = NULL; const struct kernfs_ops *ops; - struct sysfs_dirent *sd; + struct kernfs_node *kn; loff_t size; if (!is_bin) { - struct kobject *kobj = dir_sd->priv; + struct kobject *kobj = parent->priv; const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops; /* every kobject with an attribute needs a ktype assigned */ @@ -252,20 +252,20 @@ int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, if (!attr->ignore_lockdep) key = attr->key ?: (struct lock_class_key *)&attr->skey; #endif - sd = kernfs_create_file_ns_key(dir_sd, attr->name, mode, size, + kn = kernfs_create_file_ns_key(parent, attr->name, mode, size, ops, (void *)attr, ns, key); - if (IS_ERR(sd)) { - if (PTR_ERR(sd) == -EEXIST) - sysfs_warn_dup(dir_sd, attr->name); - return PTR_ERR(sd); + if (IS_ERR(kn)) { + if (PTR_ERR(kn) == -EEXIST) + sysfs_warn_dup(parent, attr->name); + return PTR_ERR(kn); } return 0; } -int sysfs_add_file(struct sysfs_dirent *dir_sd, const struct attribute *attr, +int sysfs_add_file(struct kernfs_node *parent, const struct attribute *attr, bool is_bin) { - return sysfs_add_file_mode_ns(dir_sd, attr, is_bin, attr->mode, NULL); + return sysfs_add_file_mode_ns(parent, attr, is_bin, attr->mode, NULL); } /** @@ -307,21 +307,21 @@ EXPORT_SYMBOL_GPL(sysfs_create_files); int sysfs_add_file_to_group(struct kobject *kobj, const struct attribute *attr, const char *group) { - struct sysfs_dirent *dir_sd; + struct kernfs_node *parent; int error; if (group) { - dir_sd = kernfs_find_and_get(kobj->sd, group); + parent = kernfs_find_and_get(kobj->sd, group); } else { - dir_sd = kobj->sd; - kernfs_get(dir_sd); + parent = kobj->sd; + kernfs_get(parent); } - if (!dir_sd) + if (!parent) return -ENOENT; - error = sysfs_add_file(dir_sd, attr, false); - kernfs_put(dir_sd); + error = sysfs_add_file(parent, attr, false); + kernfs_put(parent); return error; } @@ -337,20 +337,20 @@ EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, umode_t mode) { - struct sysfs_dirent *sd; + struct kernfs_node *kn; struct iattr newattrs; int rc; - sd = kernfs_find_and_get(kobj->sd, attr->name); - if (!sd) + kn = kernfs_find_and_get(kobj->sd, attr->name); + if (!kn) return -ENOENT; - newattrs.ia_mode = (mode & S_IALLUGO) | (sd->s_mode & ~S_IALLUGO); + newattrs.ia_mode = (mode & S_IALLUGO) | (kn->s_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE; - rc = kernfs_setattr(sd, &newattrs); + rc = kernfs_setattr(kn, &newattrs); - kernfs_put(sd); + kernfs_put(kn); return rc; } EXPORT_SYMBOL_GPL(sysfs_chmod_file); @@ -366,9 +366,9 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file); void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr, const void *ns) { - struct sysfs_dirent *dir_sd = kobj->sd; + struct kernfs_node *parent = kobj->sd; - kernfs_remove_by_name_ns(dir_sd, attr->name, ns); + kernfs_remove_by_name_ns(parent, attr->name, ns); } EXPORT_SYMBOL_GPL(sysfs_remove_file_ns); @@ -389,18 +389,18 @@ EXPORT_SYMBOL_GPL(sysfs_remove_files); void sysfs_remove_file_from_group(struct kobject *kobj, const struct attribute *attr, const char *group) { - struct sysfs_dirent *dir_sd; + struct kernfs_node *parent; if (group) { - dir_sd = kernfs_find_and_get(kobj->sd, group); + parent = kernfs_find_and_get(kobj->sd, group); } else { - dir_sd = kobj->sd; - kernfs_get(dir_sd); + parent = kobj->sd; + kernfs_get(parent); } - if (dir_sd) { - kernfs_remove_by_name(dir_sd, attr->name); - kernfs_put(dir_sd); + if (parent) { + kernfs_remove_by_name(parent, attr->name); + kernfs_put(parent); } } EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 7177532b8f7b..4d00d3996477 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -18,7 +18,7 @@ #include "sysfs.h" -static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, +static void remove_files(struct kernfs_node *parent, struct kobject *kobj, const struct attribute_group *grp) { struct attribute *const *attr; @@ -26,13 +26,13 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, if (grp->attrs) for (attr = grp->attrs; *attr; attr++) - kernfs_remove_by_name(dir_sd, (*attr)->name); + kernfs_remove_by_name(parent, (*attr)->name); if (grp->bin_attrs) for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) sysfs_remove_bin_file(kobj, *bin_attr); } -static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, +static int create_files(struct kernfs_node *parent, struct kobject *kobj, const struct attribute_group *grp, int update) { struct attribute *const *attr; @@ -49,20 +49,20 @@ static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, * re-adding (if required) the file. */ if (update) - kernfs_remove_by_name(dir_sd, (*attr)->name); + kernfs_remove_by_name(parent, (*attr)->name); if (grp->is_visible) { mode = grp->is_visible(kobj, *attr, i); if (!mode) continue; } - error = sysfs_add_file_mode_ns(dir_sd, *attr, false, + error = sysfs_add_file_mode_ns(parent, *attr, false, (*attr)->mode | mode, NULL); if (unlikely(error)) break; } if (error) { - remove_files(dir_sd, kobj, grp); + remove_files(parent, kobj, grp); goto exit; } } @@ -76,7 +76,7 @@ static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, break; } if (error) - remove_files(dir_sd, kobj, grp); + remove_files(parent, kobj, grp); } exit: return error; @@ -86,7 +86,7 @@ exit: static int internal_create_group(struct kobject *kobj, int update, const struct attribute_group *grp) { - struct sysfs_dirent *sd; + struct kernfs_node *kn; int error; BUG_ON(!kobj || (!update && !kobj->sd)); @@ -100,21 +100,21 @@ static int internal_create_group(struct kobject *kobj, int update, return -EINVAL; } if (grp->name) { - sd = kernfs_create_dir(kobj->sd, grp->name, kobj); - if (IS_ERR(sd)) { - if (PTR_ERR(sd) == -EEXIST) + kn = kernfs_create_dir(kobj->sd, grp->name, kobj); + if (IS_ERR(kn)) { + if (PTR_ERR(kn) == -EEXIST) sysfs_warn_dup(kobj->sd, grp->name); - return PTR_ERR(sd); + return PTR_ERR(kn); } } else - sd = kobj->sd; - kernfs_get(sd); - error = create_files(sd, kobj, grp, update); + kn = kobj->sd; + kernfs_get(kn); + error = create_files(kn, kobj, grp, update); if (error) { if (grp->name) - kernfs_remove(sd); + kernfs_remove(kn); } - kernfs_put(sd); + kernfs_put(kn); return error; } @@ -204,27 +204,27 @@ EXPORT_SYMBOL_GPL(sysfs_update_group); void sysfs_remove_group(struct kobject *kobj, const struct attribute_group *grp) { - struct sysfs_dirent *dir_sd = kobj->sd; - struct sysfs_dirent *sd; + struct kernfs_node *parent = kobj->sd; + struct kernfs_node *kn; if (grp->name) { - sd = kernfs_find_and_get(dir_sd, grp->name); - if (!sd) { - WARN(!sd, KERN_WARNING + kn = kernfs_find_and_get(parent, grp->name); + if (!kn) { + WARN(!kn, KERN_WARNING "sysfs group %p not found for kobject '%s'\n", grp, kobject_name(kobj)); return; } } else { - sd = dir_sd; - kernfs_get(sd); + kn = parent; + kernfs_get(kn); } - remove_files(sd, kobj, grp); + remove_files(kn, kobj, grp); if (grp->name) - kernfs_remove(sd); + kernfs_remove(kn); - kernfs_put(sd); + kernfs_put(kn); } EXPORT_SYMBOL_GPL(sysfs_remove_group); @@ -260,22 +260,22 @@ EXPORT_SYMBOL_GPL(sysfs_remove_groups); int sysfs_merge_group(struct kobject *kobj, const struct attribute_group *grp) { - struct sysfs_dirent *dir_sd; + struct kernfs_node *parent; int error = 0; struct attribute *const *attr; int i; - dir_sd = kernfs_find_and_get(kobj->sd, grp->name); - if (!dir_sd) + parent = kernfs_find_and_get(kobj->sd, grp->name); + if (!parent) return -ENOENT; for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr)) - error = sysfs_add_file(dir_sd, *attr, false); + error = sysfs_add_file(parent, *attr, false); if (error) { while (--i >= 0) - kernfs_remove_by_name(dir_sd, (*--attr)->name); + kernfs_remove_by_name(parent, (*--attr)->name); } - kernfs_put(dir_sd); + kernfs_put(parent); return error; } @@ -289,14 +289,14 @@ EXPORT_SYMBOL_GPL(sysfs_merge_group); void sysfs_unmerge_group(struct kobject *kobj, const struct attribute_group *grp) { - struct sysfs_dirent *dir_sd; + struct kernfs_node *parent; struct attribute *const *attr; - dir_sd = kernfs_find_and_get(kobj->sd, grp->name); - if (dir_sd) { + parent = kernfs_find_and_get(kobj->sd, grp->name); + if (parent) { for (attr = grp->attrs; *attr; ++attr) - kernfs_remove_by_name(dir_sd, (*attr)->name); - kernfs_put(dir_sd); + kernfs_remove_by_name(parent, (*attr)->name); + kernfs_put(parent); } } EXPORT_SYMBOL_GPL(sysfs_unmerge_group); @@ -311,15 +311,15 @@ EXPORT_SYMBOL_GPL(sysfs_unmerge_group); int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name, struct kobject *target, const char *link_name) { - struct sysfs_dirent *dir_sd; + struct kernfs_node *parent; int error = 0; - dir_sd = kernfs_find_and_get(kobj->sd, group_name); - if (!dir_sd) + parent = kernfs_find_and_get(kobj->sd, group_name); + if (!parent) return -ENOENT; - error = sysfs_create_link_sd(dir_sd, target, link_name); - kernfs_put(dir_sd); + error = sysfs_create_link_sd(parent, target, link_name); + kernfs_put(parent); return error; } @@ -334,12 +334,12 @@ EXPORT_SYMBOL_GPL(sysfs_add_link_to_group); void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, const char *link_name) { - struct sysfs_dirent *dir_sd; + struct kernfs_node *parent; - dir_sd = kernfs_find_and_get(kobj->sd, group_name); - if (dir_sd) { - kernfs_remove_by_name(dir_sd, link_name); - kernfs_put(dir_sd); + parent = kernfs_find_and_get(kobj->sd, group_name); + if (parent) { + kernfs_remove_by_name(parent, link_name); + kernfs_put(parent); } } EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group); diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 8d075272cace..701a56f341c6 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -20,7 +20,7 @@ #include "sysfs.h" static struct kernfs_root *sysfs_root; -struct sysfs_dirent *sysfs_root_sd; +struct kernfs_node *sysfs_root_kn; static struct dentry *sysfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) @@ -66,7 +66,7 @@ int __init sysfs_init(void) if (IS_ERR(sysfs_root)) return PTR_ERR(sysfs_root); - sysfs_root_sd = sysfs_root->sd; + sysfs_root_kn = sysfs_root->kn; err = register_filesystem(&sysfs_fs_type); if (err) { diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 1b8c9ed8511a..4ed3d49ad279 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -18,66 +18,66 @@ #include "sysfs.h" -static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, - struct kobject *target, +static int sysfs_do_create_link_sd(struct kernfs_node *parent, + struct kobject *target_kobj, const char *name, int warn) { - struct sysfs_dirent *sd, *target_sd = NULL; + struct kernfs_node *kn, *target = NULL; - BUG_ON(!name || !parent_sd); + BUG_ON(!name || !parent); /* - * We don't own @target and it may be removed at any time. + * We don't own @target_kobj and it may be removed at any time. * Synchronize using sysfs_symlink_target_lock. See * sysfs_remove_dir() for details. */ spin_lock(&sysfs_symlink_target_lock); - if (target->sd) { - target_sd = target->sd; - kernfs_get(target_sd); + if (target_kobj->sd) { + target = target_kobj->sd; + kernfs_get(target); } spin_unlock(&sysfs_symlink_target_lock); - if (!target_sd) + if (!target) return -ENOENT; - sd = kernfs_create_link(parent_sd, name, target_sd); - kernfs_put(target_sd); + kn = kernfs_create_link(parent, name, target); + kernfs_put(target); - if (!IS_ERR(sd)) + if (!IS_ERR(kn)) return 0; - if (warn && PTR_ERR(sd) == -EEXIST) - sysfs_warn_dup(parent_sd, name); - return PTR_ERR(sd); + if (warn && PTR_ERR(kn) == -EEXIST) + sysfs_warn_dup(parent, name); + return PTR_ERR(kn); } /** * sysfs_create_link_sd - create symlink to a given object. - * @sd: directory we're creating the link in. + * @kn: directory we're creating the link in. * @target: object we're pointing to. * @name: name of the symlink. */ -int sysfs_create_link_sd(struct sysfs_dirent *sd, struct kobject *target, +int sysfs_create_link_sd(struct kernfs_node *kn, struct kobject *target, const char *name) { - return sysfs_do_create_link_sd(sd, target, name, 1); + return sysfs_do_create_link_sd(kn, target, name, 1); } static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, const char *name, int warn) { - struct sysfs_dirent *parent_sd = NULL; + struct kernfs_node *parent = NULL; if (!kobj) - parent_sd = sysfs_root_sd; + parent = sysfs_root_kn; else - parent_sd = kobj->sd; + parent = kobj->sd; - if (!parent_sd) + if (!parent) return -EFAULT; - return sysfs_do_create_link_sd(parent_sd, target, name, warn); + return sysfs_do_create_link_sd(parent, target, name, warn); } /** @@ -141,14 +141,14 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, */ void sysfs_remove_link(struct kobject *kobj, const char *name) { - struct sysfs_dirent *parent_sd = NULL; + struct kernfs_node *parent = NULL; if (!kobj) - parent_sd = sysfs_root_sd; + parent = sysfs_root_kn; else - parent_sd = kobj->sd; + parent = kobj->sd; - kernfs_remove_by_name(parent_sd, name); + kernfs_remove_by_name(parent, name); } EXPORT_SYMBOL_GPL(sysfs_remove_link); @@ -165,33 +165,33 @@ EXPORT_SYMBOL_GPL(sysfs_remove_link); int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, const char *old, const char *new, const void *new_ns) { - struct sysfs_dirent *parent_sd, *sd = NULL; + struct kernfs_node *parent, *kn = NULL; const void *old_ns = NULL; int result; if (!kobj) - parent_sd = sysfs_root_sd; + parent = sysfs_root_kn; else - parent_sd = kobj->sd; + parent = kobj->sd; if (targ->sd) old_ns = targ->sd->s_ns; result = -ENOENT; - sd = kernfs_find_and_get_ns(parent_sd, old, old_ns); - if (!sd) + kn = kernfs_find_and_get_ns(parent, old, old_ns); + if (!kn) goto out; result = -EINVAL; - if (sysfs_type(sd) != SYSFS_KOBJ_LINK) + if (sysfs_type(kn) != SYSFS_KOBJ_LINK) goto out; - if (sd->s_symlink.target_sd->priv != targ) + if (kn->s_symlink.target_kn->priv != targ) goto out; - result = kernfs_rename_ns(sd, parent_sd, new, new_ns); + result = kernfs_rename_ns(kn, parent, new, new_ns); out: - kernfs_put(sd); + kernfs_put(kn); return result; } EXPORT_SYMBOL_GPL(sysfs_rename_link_ns); diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index c8e395b49330..0e2f1cccb812 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -16,28 +16,28 @@ /* * mount.c */ -extern struct sysfs_dirent *sysfs_root_sd; +extern struct kernfs_node *sysfs_root_kn; /* * dir.c */ extern spinlock_t sysfs_symlink_target_lock; -void sysfs_warn_dup(struct sysfs_dirent *parent, const char *name); +void sysfs_warn_dup(struct kernfs_node *parent, const char *name); /* * file.c */ -int sysfs_add_file(struct sysfs_dirent *dir_sd, +int sysfs_add_file(struct kernfs_node *parent, const struct attribute *attr, bool is_bin); -int sysfs_add_file_mode_ns(struct sysfs_dirent *dir_sd, +int sysfs_add_file_mode_ns(struct kernfs_node *parent, const struct attribute *attr, bool is_bin, umode_t amode, const void *ns); /* * symlink.c */ -int sysfs_create_link_sd(struct sysfs_dirent *sd, struct kobject *target, +int sysfs_create_link_sd(struct kernfs_node *kn, struct kobject *target, const char *name); #endif /* __SYSFS_INTERNAL_H */ diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index d65541308419..195d1c6a8b0c 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -46,61 +46,61 @@ enum kernfs_node_flag { SYSFS_FLAG_LOCKDEP = 0x0100, }; -/* type-specific structures for sysfs_dirent->s_* union members */ -struct sysfs_elem_dir { +/* type-specific structures for kernfs_node union members */ +struct kernfs_elem_dir { unsigned long subdirs; - /* children rbtree starts here and goes through sd->s_rb */ + /* children rbtree starts here and goes through kn->s_rb */ struct rb_root children; /* * The kernfs hierarchy this directory belongs to. This fits - * better directly in sysfs_dirent but is here to save space. + * better directly in kernfs_node but is here to save space. */ struct kernfs_root *root; }; -struct sysfs_elem_symlink { - struct sysfs_dirent *target_sd; +struct kernfs_elem_symlink { + struct kernfs_node *target_kn; }; -struct sysfs_elem_attr { +struct kernfs_elem_attr { const struct kernfs_ops *ops; struct sysfs_open_dirent *open; loff_t size; }; /* - * sysfs_dirent - the building block of sysfs hierarchy. Each and every - * sysfs node is represented by single sysfs_dirent. Most fields are + * kernfs_node - the building block of kernfs hierarchy. Each and every + * kernfs node is represented by single kernfs_node. Most fields are * private to kernfs and shouldn't be accessed directly by kernfs users. * - * As long as s_count reference is held, the sysfs_dirent itself is - * accessible. Dereferencing s_elem or any other outer entity - * requires s_active reference. + * As long as s_count reference is held, the kernfs_node itself is + * accessible. Dereferencing elem or any other outer entity requires + * active reference. */ -struct sysfs_dirent { +struct kernfs_node { atomic_t s_count; atomic_t s_active; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif /* the following two fields are published */ - struct sysfs_dirent *s_parent; + struct kernfs_node *s_parent; const char *s_name; struct rb_node s_rb; union { struct completion *completion; - struct sysfs_dirent *removed_list; + struct kernfs_node *removed_list; } u; const void *s_ns; /* namespace tag */ unsigned int s_hash; /* ns + name hash */ union { - struct sysfs_elem_dir s_dir; - struct sysfs_elem_symlink s_symlink; - struct sysfs_elem_attr s_attr; + struct kernfs_elem_dir s_dir; + struct kernfs_elem_symlink s_symlink; + struct kernfs_elem_attr s_attr; }; void *priv; @@ -113,7 +113,7 @@ struct sysfs_dirent { struct kernfs_root { /* published fields */ - struct sysfs_dirent *sd; + struct kernfs_node *kn; /* private fields, do not use outside kernfs proper */ struct ida ino_ida; @@ -121,7 +121,7 @@ struct kernfs_root { struct sysfs_open_file { /* published fields */ - struct sysfs_dirent *sd; + struct kernfs_node *kn; struct file *file; /* private fields, do not use outside kernfs proper */ @@ -170,64 +170,64 @@ struct kernfs_ops { #ifdef CONFIG_SYSFS -static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd) +static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) { - return sd->s_flags & SYSFS_TYPE_MASK; + return kn->s_flags & SYSFS_TYPE_MASK; } /** * kernfs_enable_ns - enable namespace under a directory - * @sd: directory of interest, should be empty + * @kn: directory of interest, should be empty * - * This is to be called right after @sd is created to enable namespace - * under it. All children of @sd must have non-NULL namespace tags and + * This is to be called right after @kn is created to enable namespace + * under it. All children of @kn must have non-NULL namespace tags and * only the ones which match the super_block's tag will be visible. */ -static inline void kernfs_enable_ns(struct sysfs_dirent *sd) +static inline void kernfs_enable_ns(struct kernfs_node *kn) { - WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); - WARN_ON_ONCE(!RB_EMPTY_ROOT(&sd->s_dir.children)); - sd->s_flags |= SYSFS_FLAG_NS; + WARN_ON_ONCE(sysfs_type(kn) != SYSFS_DIR); + WARN_ON_ONCE(!RB_EMPTY_ROOT(&kn->s_dir.children)); + kn->s_flags |= SYSFS_FLAG_NS; } /** * kernfs_ns_enabled - test whether namespace is enabled - * @sd: the node to test + * @kn: the node to test * * Test whether namespace filtering is enabled for the children of @ns. */ -static inline bool kernfs_ns_enabled(struct sysfs_dirent *sd) +static inline bool kernfs_ns_enabled(struct kernfs_node *kn) { - return sd->s_flags & SYSFS_FLAG_NS; + return kn->s_flags & SYSFS_FLAG_NS; } -struct sysfs_dirent *kernfs_find_and_get_ns(struct sysfs_dirent *parent, - const char *name, const void *ns); -void kernfs_get(struct sysfs_dirent *sd); -void kernfs_put(struct sysfs_dirent *sd); +struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, + const char *name, const void *ns); +void kernfs_get(struct kernfs_node *kn); +void kernfs_put(struct kernfs_node *kn); struct kernfs_root *kernfs_create_root(void *priv); void kernfs_destroy_root(struct kernfs_root *root); -struct sysfs_dirent *kernfs_create_dir_ns(struct sysfs_dirent *parent, - const char *name, void *priv, - const void *ns); -struct sysfs_dirent *kernfs_create_file_ns_key(struct sysfs_dirent *parent, - const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, - void *priv, const void *ns, - struct lock_class_key *key); -struct sysfs_dirent *kernfs_create_link(struct sysfs_dirent *parent, - const char *name, - struct sysfs_dirent *target); -void kernfs_remove(struct sysfs_dirent *sd); -int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, const char *name, +struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, + const char *name, void *priv, + const void *ns); +struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns, + struct lock_class_key *key); +struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, + const char *name, + struct kernfs_node *target); +void kernfs_remove(struct kernfs_node *kn); +int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, const void *ns); -int kernfs_rename_ns(struct sysfs_dirent *sd, struct sysfs_dirent *new_parent, +int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, const char *new_name, const void *new_ns); -int kernfs_setattr(struct sysfs_dirent *sd, const struct iattr *iattr); -void kernfs_notify(struct sysfs_dirent *sd); +int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr); +void kernfs_notify(struct kernfs_node *kn); const void *kernfs_super_ns(struct super_block *sb); struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, @@ -238,60 +238,60 @@ void kernfs_init(void); #else /* CONFIG_SYSFS */ -static inline enum kernfs_node_type sysfs_type(struct sysfs_dirent *sd) +static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) { return 0; } /* whatever */ -static inline void kernfs_enable_ns(struct sysfs_dirent *sd) { } +static inline void kernfs_enable_ns(struct kernfs_node *kn) { } -static inline bool kernfs_ns_enabled(struct sysfs_dirent *sd) +static inline bool kernfs_ns_enabled(struct kernfs_node *kn) { return false; } -static inline struct sysfs_dirent * -kernfs_find_and_get_ns(struct sysfs_dirent *parent, const char *name, +static inline struct kernfs_node * +kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name, const void *ns) { return NULL; } -static inline void kernfs_get(struct sysfs_dirent *sd) { } -static inline void kernfs_put(struct sysfs_dirent *sd) { } +static inline void kernfs_get(struct kernfs_node *kn) { } +static inline void kernfs_put(struct kernfs_node *kn) { } static inline struct kernfs_root *kernfs_create_root(void *priv) { return ERR_PTR(-ENOSYS); } static inline void kernfs_destroy_root(struct kernfs_root *root) { } -static inline struct sysfs_dirent * -kernfs_create_dir_ns(struct sysfs_dirent *parent, const char *name, void *priv, +static inline struct kernfs_node * +kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, void *priv, const void *ns) { return ERR_PTR(-ENOSYS); } -static inline struct sysfs_dirent * -kernfs_create_file_ns_key(struct sysfs_dirent *parent, const char *name, +static inline struct kernfs_node * +kernfs_create_file_ns_key(struct kernfs_node *parent, const char *name, umode_t mode, loff_t size, const struct kernfs_ops *ops, void *priv, const void *ns, struct lock_class_key *key) { return ERR_PTR(-ENOSYS); } -static inline struct sysfs_dirent * -kernfs_create_link(struct sysfs_dirent *parent, const char *name, - struct sysfs_dirent *target) +static inline struct kernfs_node * +kernfs_create_link(struct kernfs_node *parent, const char *name, + struct kernfs_node *target) { return ERR_PTR(-ENOSYS); } -static inline void kernfs_remove(struct sysfs_dirent *sd) { } +static inline void kernfs_remove(struct kernfs_node *kn) { } -static inline int kernfs_remove_by_name_ns(struct sysfs_dirent *parent, +static inline int kernfs_remove_by_name_ns(struct kernfs_node *kn, const char *name, const void *ns) { return -ENOSYS; } -static inline int kernfs_rename_ns(struct sysfs_dirent *sd, - struct sysfs_dirent *new_parent, +static inline int kernfs_rename_ns(struct kernfs_node *kn, + struct kernfs_node *new_parent, const char *new_name, const void *new_ns) { return -ENOSYS; } -static inline int kernfs_setattr(struct sysfs_dirent *sd, +static inline int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) { return -ENOSYS; } -static inline void kernfs_notify(struct sysfs_dirent *sd) { } +static inline void kernfs_notify(struct kernfs_node *kn) { } static inline const void *kernfs_super_ns(struct super_block *sb) { return NULL; } @@ -307,20 +307,20 @@ static inline void kernfs_init(void) { } #endif /* CONFIG_SYSFS */ -static inline struct sysfs_dirent * -kernfs_find_and_get(struct sysfs_dirent *sd, const char *name) +static inline struct kernfs_node * +kernfs_find_and_get(struct kernfs_node *kn, const char *name) { - return kernfs_find_and_get_ns(sd, name, NULL); + return kernfs_find_and_get_ns(kn, name, NULL); } -static inline struct sysfs_dirent * -kernfs_create_dir(struct sysfs_dirent *parent, const char *name, void *priv) +static inline struct kernfs_node * +kernfs_create_dir(struct kernfs_node *parent, const char *name, void *priv) { return kernfs_create_dir_ns(parent, name, priv, NULL); } -static inline struct sysfs_dirent * -kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name, +static inline struct kernfs_node * +kernfs_create_file_ns(struct kernfs_node *parent, const char *name, umode_t mode, loff_t size, const struct kernfs_ops *ops, void *priv, const void *ns) { @@ -333,14 +333,14 @@ kernfs_create_file_ns(struct sysfs_dirent *parent, const char *name, ns, key); } -static inline struct sysfs_dirent * -kernfs_create_file(struct sysfs_dirent *parent, const char *name, umode_t mode, +static inline struct kernfs_node * +kernfs_create_file(struct kernfs_node *parent, const char *name, umode_t mode, loff_t size, const struct kernfs_ops *ops, void *priv) { return kernfs_create_file_ns(parent, name, mode, size, ops, priv, NULL); } -static inline int kernfs_remove_by_name(struct sysfs_dirent *parent, +static inline int kernfs_remove_by_name(struct kernfs_node *parent, const char *name) { return kernfs_remove_by_name_ns(parent, name, NULL); diff --git a/include/linux/kobject.h b/include/linux/kobject.h index e7ba650086ce..926afb6f6b5f 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -64,7 +64,7 @@ struct kobject { struct kobject *parent; struct kset *kset; struct kobj_type *ktype; - struct sysfs_dirent *sd; + struct kernfs_node *sd; struct kref kref; #ifdef CONFIG_DEBUG_KOBJECT_RELEASE struct delayed_work release; diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index cd8f90bf51a7..30b2ebee6439 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h @@ -438,26 +438,26 @@ static inline int sysfs_rename_link(struct kobject *kobj, struct kobject *target return sysfs_rename_link_ns(kobj, target, old_name, new_name, NULL); } -static inline void sysfs_notify_dirent(struct sysfs_dirent *sd) +static inline void sysfs_notify_dirent(struct kernfs_node *kn) { - kernfs_notify(sd); + kernfs_notify(kn); } -static inline struct sysfs_dirent * -sysfs_get_dirent(struct sysfs_dirent *parent_sd, const unsigned char *name) +static inline struct kernfs_node *sysfs_get_dirent(struct kernfs_node *parent, + const unsigned char *name) { - return kernfs_find_and_get(parent_sd, name); + return kernfs_find_and_get(parent, name); } -static inline struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd) +static inline struct kernfs_node *sysfs_get(struct kernfs_node *kn) { - kernfs_get(sd); - return sd; + kernfs_get(kn); + return kn; } -static inline void sysfs_put(struct sysfs_dirent *sd) +static inline void sysfs_put(struct kernfs_node *kn) { - kernfs_put(sd); + kernfs_put(kn); } #endif /* _SYSFS_H_ */ diff --git a/lib/kobject.c b/lib/kobject.c index 94b321f4ac67..064451f2a6c3 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -556,7 +556,7 @@ out: */ void kobject_del(struct kobject *kobj) { - struct sysfs_dirent *sd; + struct kernfs_node *sd; if (!kobj) return; -- cgit v1.2.3-59-g8ed1b From 80b28791ff0416a472e5a555a4b6f5f39df2fc24 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 6 Nov 2013 15:45:46 -0700 Subject: ARM: tegra: pass reset to tegra_powergate_sequence_power_up() Tegra's clock driver now provides an implementation of the common reset API (include/linux/reset.h). Use this instead of the old Tegra- specific API; that will soon be removed. Signed-off-by: Stephen Warren Acked-by: Bjorn Helgaas Acked-By: Terje Bergstrom Reviewed-by: Thierry Reding Acked-by: Thierry Reding --- arch/arm/mach-tegra/powergate.c | 8 +++++--- drivers/gpu/drm/tegra/gr3d.c | 6 ++++-- drivers/pci/host/pci-tegra.c | 3 ++- include/linux/tegra-powergate.h | 7 +++++-- 4 files changed, 16 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index 85d28e756bb7..f6f5b54ff95e 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -144,11 +145,12 @@ int tegra_powergate_remove_clamping(int id) } /* Must be called with clk disabled, and returns with clk enabled */ -int tegra_powergate_sequence_power_up(int id, struct clk *clk) +int tegra_powergate_sequence_power_up(int id, struct clk *clk, + struct reset_control *rst) { int ret; - tegra_periph_reset_assert(clk); + reset_control_assert(rst); ret = tegra_powergate_power_on(id); if (ret) @@ -165,7 +167,7 @@ int tegra_powergate_sequence_power_up(int id, struct clk *clk) goto err_clamp; udelay(10); - tegra_periph_reset_deassert(clk); + reset_control_deassert(rst); return 0; diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index f629e38b00e4..0cbb24b1ae04 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -279,7 +279,8 @@ static int gr3d_probe(struct platform_device *pdev) } } - err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D, gr3d->clk); + err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D, gr3d->clk, + gr3d->rst); if (err < 0) { dev_err(&pdev->dev, "failed to power up 3D unit\n"); return err; @@ -287,7 +288,8 @@ static int gr3d_probe(struct platform_device *pdev) if (gr3d->clk_secondary) { err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1, - gr3d->clk_secondary); + gr3d->clk_secondary, + gr3d->rst_secondary); if (err < 0) { dev_err(&pdev->dev, "failed to power up secondary 3D unit\n"); diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 6681c3182c85..0175041ab728 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -955,7 +955,8 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) } err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, - pcie->pex_clk); + pcie->pex_clk, + pcie->pex_rst); if (err) { dev_err(pcie->dev, "powerup sequence failed: %d\n", err); return err; diff --git a/include/linux/tegra-powergate.h b/include/linux/tegra-powergate.h index fd4498329c7c..afe442d2629a 100644 --- a/include/linux/tegra-powergate.h +++ b/include/linux/tegra-powergate.h @@ -19,6 +19,7 @@ #define _MACH_TEGRA_POWERGATE_H_ struct clk; +struct reset_control; #define TEGRA_POWERGATE_CPU 0 #define TEGRA_POWERGATE_3D 1 @@ -52,7 +53,8 @@ int tegra_powergate_power_off(int id); int tegra_powergate_remove_clamping(int id); /* Must be called with clk disabled, and returns with clk enabled */ -int tegra_powergate_sequence_power_up(int id, struct clk *clk); +int tegra_powergate_sequence_power_up(int id, struct clk *clk, + struct reset_control *rst); #else static inline int tegra_powergate_is_powered(int id) { @@ -74,7 +76,8 @@ static inline int tegra_powergate_remove_clamping(int id) return -ENOSYS; } -static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk) +static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk, + struct reset_control *rst); { return -ENOSYS; } -- cgit v1.2.3-59-g8ed1b From adc5e8b58f4886d45f79f4ff41a09001a76a6b12 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:54 -0500 Subject: kernfs: drop s_ prefix from kernfs_node members kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. s_ prefix for kernfs members is used inconsistently and a misnomer now. It's not like kernfs_node is used widely across the kernel making the ability to grep for the members particularly useful. Let's just drop the prefix. This patch is strictly rename only and doesn't introduce any functional difference. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 198 ++++++++++++++++++++++---------------------- fs/kernfs/file.c | 52 ++++++------ fs/kernfs/inode.c | 30 +++---- fs/kernfs/kernfs-internal.h | 6 +- fs/kernfs/symlink.c | 32 +++---- fs/sysfs/dir.c | 12 +-- fs/sysfs/file.c | 16 ++-- fs/sysfs/symlink.c | 6 +- include/linux/kernfs.h | 38 ++++----- 9 files changed, 193 insertions(+), 197 deletions(-) (limited to 'include/linux') diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 800ebf521472..51fff9d2b334 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -19,7 +19,7 @@ DEFINE_MUTEX(sysfs_mutex); -#define rb_to_kn(X) rb_entry((X), struct kernfs_node, s_rb) +#define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb) /** * sysfs_name_hash @@ -47,18 +47,17 @@ static unsigned int sysfs_name_hash(const char *name, const void *ns) static int sysfs_name_compare(unsigned int hash, const char *name, const void *ns, const struct kernfs_node *kn) { - if (hash != kn->s_hash) - return hash - kn->s_hash; - if (ns != kn->s_ns) - return ns - kn->s_ns; - return strcmp(name, kn->s_name); + if (hash != kn->hash) + return hash - kn->hash; + if (ns != kn->ns) + return ns - kn->ns; + return strcmp(name, kn->name); } static int sysfs_sd_compare(const struct kernfs_node *left, const struct kernfs_node *right) { - return sysfs_name_compare(left->s_hash, left->s_name, left->s_ns, - right); + return sysfs_name_compare(left->hash, left->name, left->ns, right); } /** @@ -66,7 +65,7 @@ static int sysfs_sd_compare(const struct kernfs_node *left, * @kn: kernfs_node of interest * * Link @kn into its sibling rbtree which starts from - * @kn->s_parent->s_dir.children. + * @kn->parent->dir.children. * * Locking: * mutex_lock(sysfs_mutex) @@ -76,11 +75,11 @@ static int sysfs_sd_compare(const struct kernfs_node *left, */ static int sysfs_link_sibling(struct kernfs_node *kn) { - struct rb_node **node = &kn->s_parent->s_dir.children.rb_node; + struct rb_node **node = &kn->parent->dir.children.rb_node; struct rb_node *parent = NULL; if (sysfs_type(kn) == SYSFS_DIR) - kn->s_parent->s_dir.subdirs++; + kn->parent->dir.subdirs++; while (*node) { struct kernfs_node *pos; @@ -90,15 +89,15 @@ static int sysfs_link_sibling(struct kernfs_node *kn) parent = *node; result = sysfs_sd_compare(kn, pos); if (result < 0) - node = &pos->s_rb.rb_left; + node = &pos->rb.rb_left; else if (result > 0) - node = &pos->s_rb.rb_right; + node = &pos->rb.rb_right; else return -EEXIST; } /* add new node and rebalance the tree */ - rb_link_node(&kn->s_rb, parent, node); - rb_insert_color(&kn->s_rb, &kn->s_parent->s_dir.children); + rb_link_node(&kn->rb, parent, node); + rb_insert_color(&kn->rb, &kn->parent->dir.children); return 0; } @@ -107,7 +106,7 @@ static int sysfs_link_sibling(struct kernfs_node *kn) * @kn: kernfs_node of interest * * Unlink @kn from its sibling rbtree which starts from - * kn->s_parent->s_dir.children. + * kn->parent->dir.children. * * Locking: * mutex_lock(sysfs_mutex) @@ -115,9 +114,9 @@ static int sysfs_link_sibling(struct kernfs_node *kn) static void sysfs_unlink_sibling(struct kernfs_node *kn) { if (sysfs_type(kn) == SYSFS_DIR) - kn->s_parent->s_dir.subdirs--; + kn->parent->dir.subdirs--; - rb_erase(&kn->s_rb, &kn->s_parent->s_dir.children); + rb_erase(&kn->rb, &kn->parent->dir.children); } /** @@ -135,10 +134,10 @@ struct kernfs_node *sysfs_get_active(struct kernfs_node *kn) if (unlikely(!kn)) return NULL; - if (!atomic_inc_unless_negative(&kn->s_active)) + if (!atomic_inc_unless_negative(&kn->active)) return NULL; - if (kn->s_flags & SYSFS_FLAG_LOCKDEP) + if (kn->flags & SYSFS_FLAG_LOCKDEP) rwsem_acquire_read(&kn->dep_map, 0, 1, _RET_IP_); return kn; } @@ -157,9 +156,9 @@ void sysfs_put_active(struct kernfs_node *kn) if (unlikely(!kn)) return; - if (kn->s_flags & SYSFS_FLAG_LOCKDEP) + if (kn->flags & SYSFS_FLAG_LOCKDEP) rwsem_release(&kn->dep_map, 1, _RET_IP_); - v = atomic_dec_return(&kn->s_active); + v = atomic_dec_return(&kn->active); if (likely(v != SD_DEACTIVATED_BIAS)) return; @@ -181,7 +180,7 @@ static void sysfs_deactivate(struct kernfs_node *kn) DECLARE_COMPLETION_ONSTACK(wait); int v; - BUG_ON(!(kn->s_flags & SYSFS_FLAG_REMOVED)); + BUG_ON(!(kn->flags & SYSFS_FLAG_REMOVED)); if (!(sysfs_type(kn) & SYSFS_ACTIVE_REF)) return; @@ -192,7 +191,7 @@ static void sysfs_deactivate(struct kernfs_node *kn) /* atomic_add_return() is a mb(), put_active() will always see * the updated kn->u.completion. */ - v = atomic_add_return(SD_DEACTIVATED_BIAS, &kn->s_active); + v = atomic_add_return(SD_DEACTIVATED_BIAS, &kn->active); if (v != SD_DEACTIVATED_BIAS) { lock_contended(&kn->dep_map, _RET_IP_); @@ -210,8 +209,8 @@ static void sysfs_deactivate(struct kernfs_node *kn) void kernfs_get(struct kernfs_node *kn) { if (kn) { - WARN_ON(!atomic_read(&kn->s_count)); - atomic_inc(&kn->s_count); + WARN_ON(!atomic_read(&kn->count)); + atomic_inc(&kn->count); } } EXPORT_SYMBOL_GPL(kernfs_get); @@ -227,36 +226,36 @@ void kernfs_put(struct kernfs_node *kn) struct kernfs_node *parent; struct kernfs_root *root; - if (!kn || !atomic_dec_and_test(&kn->s_count)) + if (!kn || !atomic_dec_and_test(&kn->count)) return; root = kernfs_root(kn); repeat: /* Moving/renaming is always done while holding reference. - * kn->s_parent won't change beneath us. + * kn->parent won't change beneath us. */ - parent = kn->s_parent; + parent = kn->parent; - WARN(!(kn->s_flags & SYSFS_FLAG_REMOVED), + WARN(!(kn->flags & SYSFS_FLAG_REMOVED), "sysfs: free using entry: %s/%s\n", - parent ? parent->s_name : "", kn->s_name); + parent ? parent->name : "", kn->name); if (sysfs_type(kn) == SYSFS_KOBJ_LINK) - kernfs_put(kn->s_symlink.target_kn); + kernfs_put(kn->symlink.target_kn); if (sysfs_type(kn) & SYSFS_COPY_NAME) - kfree(kn->s_name); - if (kn->s_iattr) { - if (kn->s_iattr->ia_secdata) - security_release_secctx(kn->s_iattr->ia_secdata, - kn->s_iattr->ia_secdata_len); - simple_xattrs_free(&kn->s_iattr->xattrs); + kfree(kn->name); + if (kn->iattr) { + if (kn->iattr->ia_secdata) + security_release_secctx(kn->iattr->ia_secdata, + kn->iattr->ia_secdata_len); + simple_xattrs_free(&kn->iattr->xattrs); } - kfree(kn->s_iattr); - ida_simple_remove(&root->ino_ida, kn->s_ino); + kfree(kn->iattr); + ida_simple_remove(&root->ino_ida, kn->ino); kmem_cache_free(sysfs_dir_cachep, kn); kn = parent; if (kn) { - if (atomic_dec_and_test(&kn->s_count)) + if (atomic_dec_and_test(&kn->count)) goto repeat; } else { /* just released the root kn, free @root too */ @@ -269,7 +268,7 @@ EXPORT_SYMBOL_GPL(kernfs_put); static int sysfs_dentry_delete(const struct dentry *dentry) { struct kernfs_node *kn = dentry->d_fsdata; - return !(kn && !(kn->s_flags & SYSFS_FLAG_REMOVED)); + return !(kn && !(kn->flags & SYSFS_FLAG_REMOVED)); } static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) @@ -283,20 +282,20 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) mutex_lock(&sysfs_mutex); /* The sysfs dirent has been deleted */ - if (kn->s_flags & SYSFS_FLAG_REMOVED) + if (kn->flags & SYSFS_FLAG_REMOVED) goto out_bad; /* The sysfs dirent has been moved? */ - if (dentry->d_parent->d_fsdata != kn->s_parent) + if (dentry->d_parent->d_fsdata != kn->parent) goto out_bad; /* The sysfs dirent has been renamed */ - if (strcmp(dentry->d_name.name, kn->s_name) != 0) + if (strcmp(dentry->d_name.name, kn->name) != 0) goto out_bad; /* The sysfs dirent has been moved to a different namespace */ - if (kn->s_parent && kernfs_ns_enabled(kn->s_parent) && - sysfs_info(dentry->d_sb)->ns != kn->s_ns) + if (kn->parent && kernfs_ns_enabled(kn->parent) && + sysfs_info(dentry->d_sb)->ns != kn->ns) goto out_bad; mutex_unlock(&sysfs_mutex); @@ -356,14 +355,14 @@ struct kernfs_node *sysfs_new_dirent(struct kernfs_root *root, ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL); if (ret < 0) goto err_out2; - kn->s_ino = ret; + kn->ino = ret; - atomic_set(&kn->s_count, 1); - atomic_set(&kn->s_active, 0); + atomic_set(&kn->count, 1); + atomic_set(&kn->active, 0); - kn->s_name = name; - kn->s_mode = mode; - kn->s_flags = type | SYSFS_FLAG_REMOVED; + kn->name = name; + kn->mode = mode; + kn->flags = type | SYSFS_FLAG_REMOVED; return kn; @@ -400,9 +399,9 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt) * @kn: kernfs_node to be added * @parent: the parent kernfs_node to add @kn to * - * Get @parent and set @kn->s_parent to it and increment nlink of - * the parent inode if @kn is a directory and link into the children - * list of the parent. + * Get @parent and set @kn->parent to it and increment nlink of the + * parent inode if @kn is a directory and link into the children list + * of the parent. * * This function should be called between calls to * sysfs_addrm_start() and sysfs_addrm_finish() and should be @@ -422,18 +421,17 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct kernfs_node *kn, struct sysfs_inode_attrs *ps_iattr; int ret; - if (has_ns != (bool)kn->s_ns) { + if (has_ns != (bool)kn->ns) { WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", - has_ns ? "required" : "invalid", - parent->s_name, kn->s_name); + has_ns ? "required" : "invalid", parent->name, kn->name); return -EINVAL; } if (sysfs_type(parent) != SYSFS_DIR) return -EINVAL; - kn->s_hash = sysfs_name_hash(kn->s_name, kn->s_ns); - kn->s_parent = parent; + kn->hash = sysfs_name_hash(kn->name, kn->ns); + kn->parent = parent; kernfs_get(parent); ret = sysfs_link_sibling(kn); @@ -441,14 +439,14 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct kernfs_node *kn, return ret; /* Update timestamps on the parent */ - ps_iattr = parent->s_iattr; + ps_iattr = parent->iattr; if (ps_iattr) { struct iattr *ps_iattrs = &ps_iattr->ia_iattr; ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME; } /* Mark the entry added into directory tree */ - kn->s_flags &= ~SYSFS_FLAG_REMOVED; + kn->flags &= ~SYSFS_FLAG_REMOVED; return 0; } @@ -477,21 +475,21 @@ static void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, * Removal can be called multiple times on the same node. Only the * first invocation is effective and puts the base ref. */ - if (kn->s_flags & SYSFS_FLAG_REMOVED) + if (kn->flags & SYSFS_FLAG_REMOVED) return; - if (kn->s_parent) { + if (kn->parent) { sysfs_unlink_sibling(kn); /* Update timestamps on the parent */ - ps_iattr = kn->s_parent->s_iattr; + ps_iattr = kn->parent->iattr; if (ps_iattr) { ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME; ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME; } } - kn->s_flags |= SYSFS_FLAG_REMOVED; + kn->flags |= SYSFS_FLAG_REMOVED; kn->u.removed_list = acxt->removed; acxt->removed = kn; } @@ -538,7 +536,7 @@ static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, const unsigned char *name, const void *ns) { - struct rb_node *node = parent->s_dir.children.rb_node; + struct rb_node *node = parent->dir.children.rb_node; bool has_ns = kernfs_ns_enabled(parent); unsigned int hash; @@ -546,8 +544,7 @@ static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, if (has_ns != (bool)ns) { WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", - has_ns ? "required" : "invalid", - parent->s_name, name); + has_ns ? "required" : "invalid", parent->name, name); return NULL; } @@ -617,9 +614,9 @@ struct kernfs_root *kernfs_create_root(void *priv) return ERR_PTR(-ENOMEM); } - kn->s_flags &= ~SYSFS_FLAG_REMOVED; + kn->flags &= ~SYSFS_FLAG_REMOVED; kn->priv = priv; - kn->s_dir.root = root; + kn->dir.root = root; root->kn = kn; @@ -661,8 +658,8 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, if (!kn) return ERR_PTR(-ENOMEM); - kn->s_dir.root = parent->s_dir.root; - kn->s_ns = ns; + kn->dir.root = parent->dir.root; + kn->ns = ns; kn->priv = priv; /* link in */ @@ -738,7 +735,7 @@ static struct kernfs_node *sysfs_leftmost_descendant(struct kernfs_node *pos) if (sysfs_type(pos) != SYSFS_DIR) break; - rbn = rb_first(&pos->s_dir.children); + rbn = rb_first(&pos->dir.children); if (!rbn) break; @@ -773,12 +770,12 @@ static struct kernfs_node *sysfs_next_descendant_post(struct kernfs_node *pos, return NULL; /* if there's an unvisited sibling, visit its leftmost descendant */ - rbn = rb_next(&pos->s_rb); + rbn = rb_next(&pos->rb); if (rbn) return sysfs_leftmost_descendant(rb_to_kn(rbn)); /* no sibling left, visit parent */ - return pos->s_parent; + return pos->parent; } static void __kernfs_remove(struct sysfs_addrm_cxt *acxt, @@ -789,7 +786,7 @@ static void __kernfs_remove(struct sysfs_addrm_cxt *acxt, if (!kn) return; - pr_debug("sysfs %s: removing\n", kn->s_name); + pr_debug("sysfs %s: removing\n", kn->name); next = NULL; do { @@ -865,8 +862,8 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, mutex_lock(&sysfs_mutex); error = 0; - if ((kn->s_parent == new_parent) && (kn->s_ns == new_ns) && - (strcmp(kn->s_name, new_name) == 0)) + if ((kn->parent == new_parent) && (kn->ns == new_ns) && + (strcmp(kn->name, new_name) == 0)) goto out; /* nothing to rename */ error = -EEXIST; @@ -874,14 +871,14 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, goto out; /* rename kernfs_node */ - if (strcmp(kn->s_name, new_name) != 0) { + if (strcmp(kn->name, new_name) != 0) { error = -ENOMEM; new_name = kstrdup(new_name, GFP_KERNEL); if (!new_name) goto out; - kfree(kn->s_name); - kn->s_name = new_name; + kfree(kn->name); + kn->name = new_name; } /* @@ -889,10 +886,10 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, */ sysfs_unlink_sibling(kn); kernfs_get(new_parent); - kernfs_put(kn->s_parent); - kn->s_ns = new_ns; - kn->s_hash = sysfs_name_hash(kn->s_name, kn->s_ns); - kn->s_parent = new_parent; + kernfs_put(kn->parent); + kn->ns = new_ns; + kn->hash = sysfs_name_hash(kn->name, kn->ns); + kn->parent = new_parent; sysfs_link_sibling(kn); error = 0; @@ -904,7 +901,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, /* Relationship between s_mode and the DT_xxx types */ static inline unsigned char dt_type(struct kernfs_node *kn) { - return (kn->s_mode >> 12) & 15; + return (kn->mode >> 12) & 15; } static int sysfs_dir_release(struct inode *inode, struct file *filp) @@ -917,29 +914,28 @@ static struct kernfs_node *sysfs_dir_pos(const void *ns, struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos) { if (pos) { - int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && - pos->s_parent == parent && - hash == pos->s_hash; + int valid = !(pos->flags & SYSFS_FLAG_REMOVED) && + pos->parent == parent && hash == pos->hash; kernfs_put(pos); if (!valid) pos = NULL; } if (!pos && (hash > 1) && (hash < INT_MAX)) { - struct rb_node *node = parent->s_dir.children.rb_node; + struct rb_node *node = parent->dir.children.rb_node; while (node) { pos = rb_to_kn(node); - if (hash < pos->s_hash) + if (hash < pos->hash) node = node->rb_left; - else if (hash > pos->s_hash) + else if (hash > pos->hash) node = node->rb_right; else break; } } /* Skip over entries in the wrong namespace */ - while (pos && pos->s_ns != ns) { - struct rb_node *node = rb_next(&pos->s_rb); + while (pos && pos->ns != ns) { + struct rb_node *node = rb_next(&pos->rb); if (!node) pos = NULL; else @@ -954,12 +950,12 @@ static struct kernfs_node *sysfs_dir_next_pos(const void *ns, pos = sysfs_dir_pos(ns, parent, ino, pos); if (pos) do { - struct rb_node *node = rb_next(&pos->s_rb); + struct rb_node *node = rb_next(&pos->rb); if (!node) pos = NULL; else pos = rb_to_kn(node); - } while (pos && pos->s_ns != ns); + } while (pos && pos->ns != ns); return pos; } @@ -980,12 +976,12 @@ static int sysfs_readdir(struct file *file, struct dir_context *ctx) for (pos = sysfs_dir_pos(ns, parent, ctx->pos, pos); pos; pos = sysfs_dir_next_pos(ns, parent, ctx->pos, pos)) { - const char *name = pos->s_name; + const char *name = pos->name; unsigned int type = dt_type(pos); int len = strlen(name); - ino_t ino = pos->s_ino; + ino_t ino = pos->ino; - ctx->pos = pos->s_hash; + ctx->pos = pos->hash; file->private_data = pos; kernfs_get(pos); diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 1bf07ded826a..5277021196a7 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -21,7 +21,7 @@ * There's one sysfs_open_file for each open file and one sysfs_open_dirent * for each kernfs_node with one or more open files. * - * kernfs_node->s_attr.open points to sysfs_open_dirent. s_attr.open is + * kernfs_node->attr.open points to sysfs_open_dirent. attr.open is * protected by sysfs_open_dirent_lock. * * filp->private_data points to seq_file whose ->private points to @@ -49,9 +49,9 @@ static struct sysfs_open_file *sysfs_of(struct file *file) */ static const struct kernfs_ops *kernfs_ops(struct kernfs_node *kn) { - if (kn->s_flags & SYSFS_FLAG_LOCKDEP) + if (kn->flags & SYSFS_FLAG_LOCKDEP) lockdep_assert_held(kn); - return kn->s_attr.ops; + return kn->attr.ops; } static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) @@ -112,9 +112,9 @@ static int kernfs_seq_show(struct seq_file *sf, void *v) { struct sysfs_open_file *of = sf->private; - of->event = atomic_read(&of->kn->s_attr.open->event); + of->event = atomic_read(&of->kn->attr.open->event); - return of->kn->s_attr.ops->seq_show(sf, v); + return of->kn->attr.ops->seq_show(sf, v); } static const struct seq_operations kernfs_seq_ops = { @@ -189,7 +189,7 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, { struct sysfs_open_file *of = sysfs_of(file); - if (of->kn->s_flags & SYSFS_FLAG_HAS_SEQ_SHOW) + if (of->kn->flags & SYSFS_FLAG_HAS_SEQ_SHOW) return seq_read(file, user_buf, count, ppos); else return kernfs_file_direct_read(of, user_buf, count, ppos); @@ -428,7 +428,7 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) * without grabbing @of->mutex by testing HAS_MMAP flag. See the * comment in kernfs_file_open() for more details. */ - if (!(of->kn->s_flags & SYSFS_FLAG_HAS_MMAP)) + if (!(of->kn->flags & SYSFS_FLAG_HAS_MMAP)) return -ENODEV; mutex_lock(&of->mutex); @@ -477,8 +477,8 @@ out_unlock: * @kn: target kernfs_node * @of: sysfs_open_file for this instance of open * - * If @kn->s_attr.open exists, increment its reference count; - * otherwise, create one. @of is chained to the files list. + * If @kn->attr.open exists, increment its reference count; otherwise, + * create one. @of is chained to the files list. * * LOCKING: * Kernel thread context (may sleep). @@ -495,12 +495,12 @@ static int sysfs_get_open_dirent(struct kernfs_node *kn, mutex_lock(&sysfs_open_file_mutex); spin_lock_irq(&sysfs_open_dirent_lock); - if (!kn->s_attr.open && new_od) { - kn->s_attr.open = new_od; + if (!kn->attr.open && new_od) { + kn->attr.open = new_od; new_od = NULL; } - od = kn->s_attr.open; + od = kn->attr.open; if (od) { atomic_inc(&od->refcnt); list_add_tail(&of->list, &od->files); @@ -531,7 +531,7 @@ static int sysfs_get_open_dirent(struct kernfs_node *kn, * @kn: target kernfs_nodet * @of: associated sysfs_open_file * - * Put @kn->s_attr.open and unlink @of from the files list. If + * Put @kn->attr.open and unlink @of from the files list. If * reference count reaches zero, disassociate and free it. * * LOCKING: @@ -540,7 +540,7 @@ static int sysfs_get_open_dirent(struct kernfs_node *kn, static void sysfs_put_open_dirent(struct kernfs_node *kn, struct sysfs_open_file *of) { - struct sysfs_open_dirent *od = kn->s_attr.open; + struct sysfs_open_dirent *od = kn->attr.open; unsigned long flags; mutex_lock(&sysfs_open_file_mutex); @@ -550,7 +550,7 @@ static void sysfs_put_open_dirent(struct kernfs_node *kn, list_del(&of->list); if (atomic_dec_and_test(&od->refcnt)) - kn->s_attr.open = NULL; + kn->attr.open = NULL; else od = NULL; @@ -668,11 +668,11 @@ void sysfs_unmap_bin_file(struct kernfs_node *kn) struct sysfs_open_dirent *od; struct sysfs_open_file *of; - if (!(kn->s_flags & SYSFS_FLAG_HAS_MMAP)) + if (!(kn->flags & SYSFS_FLAG_HAS_MMAP)) return; spin_lock_irq(&sysfs_open_dirent_lock); - od = kn->s_attr.open; + od = kn->attr.open; if (od) atomic_inc(&od->refcnt); spin_unlock_irq(&sysfs_open_dirent_lock); @@ -706,7 +706,7 @@ static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) { struct sysfs_open_file *of = sysfs_of(filp); struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; - struct sysfs_open_dirent *od = kn->s_attr.open; + struct sysfs_open_dirent *od = kn->attr.open; /* need parent for the kobj, grab both */ if (!sysfs_get_active(kn)) @@ -739,7 +739,7 @@ void kernfs_notify(struct kernfs_node *kn) spin_lock_irqsave(&sysfs_open_dirent_lock, flags); if (!WARN_ON(sysfs_type(kn) != SYSFS_KOBJ_ATTR)) { - od = kn->s_attr.open; + od = kn->attr.open; if (od) { atomic_inc(&od->event); wake_up_interruptible(&od->poll); @@ -789,27 +789,27 @@ struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, if (!kn) return ERR_PTR(-ENOMEM); - kn->s_attr.ops = ops; - kn->s_attr.size = size; - kn->s_ns = ns; + kn->attr.ops = ops; + kn->attr.size = size; + kn->ns = ns; kn->priv = priv; #ifdef CONFIG_DEBUG_LOCK_ALLOC if (key) { lockdep_init_map(&kn->dep_map, "s_active", key, 0); - kn->s_flags |= SYSFS_FLAG_LOCKDEP; + kn->flags |= SYSFS_FLAG_LOCKDEP; } #endif /* - * kn->s_attr.ops is accesible only while holding active ref. We + * kn->attr.ops is accesible only while holding active ref. We * need to know whether some ops are implemented outside active * ref. Cache their existence in flags. */ if (ops->seq_show) - kn->s_flags |= SYSFS_FLAG_HAS_SEQ_SHOW; + kn->flags |= SYSFS_FLAG_HAS_SEQ_SHOW; if (ops->mmap) - kn->s_flags |= SYSFS_FLAG_HAS_MMAP; + kn->flags |= SYSFS_FLAG_HAS_MMAP; sysfs_addrm_start(&acxt); rc = sysfs_add_one(&acxt, kn, parent); diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index 9e74eed63539..f6c0aae3dd5c 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -50,23 +50,23 @@ static struct sysfs_inode_attrs *sysfs_inode_attrs(struct kernfs_node *kn) { struct iattr *iattrs; - if (kn->s_iattr) - return kn->s_iattr; + if (kn->iattr) + return kn->iattr; - kn->s_iattr = kzalloc(sizeof(struct sysfs_inode_attrs), GFP_KERNEL); - if (!kn->s_iattr) + kn->iattr = kzalloc(sizeof(struct sysfs_inode_attrs), GFP_KERNEL); + if (!kn->iattr) return NULL; - iattrs = &kn->s_iattr->ia_iattr; + iattrs = &kn->iattr->ia_iattr; /* assign default attributes */ - iattrs->ia_mode = kn->s_mode; + iattrs->ia_mode = kn->mode; iattrs->ia_uid = GLOBAL_ROOT_UID; iattrs->ia_gid = GLOBAL_ROOT_GID; iattrs->ia_atime = iattrs->ia_mtime = iattrs->ia_ctime = CURRENT_TIME; - simple_xattrs_init(&kn->s_iattr->xattrs); + simple_xattrs_init(&kn->iattr->xattrs); - return kn->s_iattr; + return kn->iattr; } static int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) @@ -93,7 +93,7 @@ static int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) iattrs->ia_ctime = iattr->ia_ctime; if (ia_valid & ATTR_MODE) { umode_t mode = iattr->ia_mode; - iattrs->ia_mode = kn->s_mode = mode; + iattrs->ia_mode = kn->mode = mode; } return 0; } @@ -256,9 +256,9 @@ static inline void set_inode_attr(struct inode *inode, struct iattr *iattr) static void sysfs_refresh_inode(struct kernfs_node *kn, struct inode *inode) { - struct sysfs_inode_attrs *attrs = kn->s_iattr; + struct sysfs_inode_attrs *attrs = kn->iattr; - inode->i_mode = kn->s_mode; + inode->i_mode = kn->mode; if (attrs) { /* * kernfs_node has non-default attributes get them from @@ -270,7 +270,7 @@ static void sysfs_refresh_inode(struct kernfs_node *kn, struct inode *inode) } if (sysfs_type(kn) == SYSFS_DIR) - set_nlink(inode, kn->s_dir.subdirs + 2); + set_nlink(inode, kn->dir.subdirs + 2); } int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, @@ -295,7 +295,7 @@ static void sysfs_init_inode(struct kernfs_node *kn, struct inode *inode) inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info; inode->i_op = &sysfs_inode_operations; - set_default_inode_attr(inode, kn->s_mode); + set_default_inode_attr(inode, kn->mode); sysfs_refresh_inode(kn, inode); /* initialize inode according to type */ @@ -305,7 +305,7 @@ static void sysfs_init_inode(struct kernfs_node *kn, struct inode *inode) inode->i_fop = &sysfs_dir_operations; break; case SYSFS_KOBJ_ATTR: - inode->i_size = kn->s_attr.size; + inode->i_size = kn->attr.size; inode->i_fop = &kernfs_file_operations; break; case SYSFS_KOBJ_LINK: @@ -337,7 +337,7 @@ struct inode *sysfs_get_inode(struct super_block *sb, struct kernfs_node *kn) { struct inode *inode; - inode = iget_locked(sb, kn->s_ino); + inode = iget_locked(sb, kn->ino); if (inode && (inode->i_state & I_NEW)) sysfs_init_inode(kn, inode); diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index b7ea76c6fb33..2dbb1cb95e7f 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -39,9 +39,9 @@ struct sysfs_inode_attrs { static inline struct kernfs_root *kernfs_root(struct kernfs_node *kn) { /* if parent exists, it's always a dir; otherwise, @sd is a dir */ - if (kn->s_parent) - kn = kn->s_parent; - return kn->s_dir.root; + if (kn->parent) + kn = kn->parent; + return kn->dir.root; } /* diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index 29dcf5e8debd..5ac1a57c3807 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -36,8 +36,8 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, return ERR_PTR(-ENOMEM); if (kernfs_ns_enabled(parent)) - kn->s_ns = target->s_ns; - kn->s_symlink.target_kn = target; + kn->ns = target->ns; + kn->symlink.target_kn = target; kernfs_get(target); /* ref owned by symlink */ sysfs_addrm_start(&acxt); @@ -60,24 +60,24 @@ static int sysfs_get_target_path(struct kernfs_node *parent, /* go up to the root, stop at the base */ base = parent; - while (base->s_parent) { - kn = target->s_parent; - while (kn->s_parent && base != kn) - kn = kn->s_parent; + while (base->parent) { + kn = target->parent; + while (kn->parent && base != kn) + kn = kn->parent; if (base == kn) break; strcpy(s, "../"); s += 3; - base = base->s_parent; + base = base->parent; } /* determine end of target string for reverse fillup */ kn = target; - while (kn->s_parent && kn != base) { - len += strlen(kn->s_name) + 1; - kn = kn->s_parent; + while (kn->parent && kn != base) { + len += strlen(kn->name) + 1; + kn = kn->parent; } /* check limits */ @@ -89,15 +89,15 @@ static int sysfs_get_target_path(struct kernfs_node *parent, /* reverse fillup of target string from target to base */ kn = target; - while (kn->s_parent && kn != base) { - int slen = strlen(kn->s_name); + while (kn->parent && kn != base) { + int slen = strlen(kn->name); len -= slen; - strncpy(s + len, kn->s_name, slen); + strncpy(s + len, kn->name, slen); if (len) s[--len] = '/'; - kn = kn->s_parent; + kn = kn->parent; } return 0; @@ -106,8 +106,8 @@ static int sysfs_get_target_path(struct kernfs_node *parent, static int sysfs_getlink(struct dentry *dentry, char *path) { struct kernfs_node *kn = dentry->d_fsdata; - struct kernfs_node *parent = kn->s_parent; - struct kernfs_node *target = kn->s_symlink.target_kn; + struct kernfs_node *parent = kn->parent; + struct kernfs_node *target = kn->symlink.target_kn; int error; mutex_lock(&sysfs_mutex); diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index f1efe3df0de6..4a800017558d 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -29,11 +29,11 @@ DEFINE_SPINLOCK(sysfs_symlink_target_lock); */ static char *sysfs_pathname(struct kernfs_node *kn, char *path) { - if (kn->s_parent) { - sysfs_pathname(kn->s_parent, path); + if (kn->parent) { + sysfs_pathname(kn->parent, path); strlcat(path, "/", PATH_MAX); } - strlcat(path, kn->s_name, PATH_MAX); + strlcat(path, kn->name, PATH_MAX); return path; } @@ -121,7 +121,7 @@ void sysfs_remove_dir(struct kobject *kobj) int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, const void *new_ns) { - struct kernfs_node *parent = kobj->sd->s_parent; + struct kernfs_node *parent = kobj->sd->parent; return kernfs_rename_ns(kobj->sd, parent, new_name, new_ns); } @@ -132,9 +132,9 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, struct kernfs_node *kn = kobj->sd; struct kernfs_node *new_parent; - BUG_ON(!kn->s_parent); + BUG_ON(!kn->parent); new_parent = new_parent_kobj && new_parent_kobj->sd ? new_parent_kobj->sd : sysfs_root_kn; - return kernfs_rename_ns(kn, new_parent, kn->s_name, new_ns); + return kernfs_rename_ns(kn, new_parent, kn->name, new_ns); } diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index be1cc39035bd..887703a79065 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -27,9 +27,9 @@ */ static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn) { - struct kobject *kobj = kn->s_parent->priv; + struct kobject *kobj = kn->parent->priv; - if (kn->s_flags & SYSFS_FLAG_LOCKDEP) + if (kn->flags & SYSFS_FLAG_LOCKDEP) lockdep_assert_held(kn); return kobj->ktype ? kobj->ktype->sysfs_ops : NULL; } @@ -42,7 +42,7 @@ static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn) static int sysfs_kf_seq_show(struct seq_file *sf, void *v) { struct sysfs_open_file *of = sf->private; - struct kobject *kobj = of->kn->s_parent->priv; + struct kobject *kobj = of->kn->parent->priv; const struct sysfs_ops *ops = sysfs_file_ops(of->kn); ssize_t count; char *buf; @@ -82,7 +82,7 @@ static ssize_t sysfs_kf_bin_read(struct sysfs_open_file *of, char *buf, size_t count, loff_t pos) { struct bin_attribute *battr = of->kn->priv; - struct kobject *kobj = of->kn->s_parent->priv; + struct kobject *kobj = of->kn->parent->priv; loff_t size = file_inode(of->file)->i_size; if (!count) @@ -106,7 +106,7 @@ static ssize_t sysfs_kf_write(struct sysfs_open_file *of, char *buf, size_t count, loff_t pos) { const struct sysfs_ops *ops = sysfs_file_ops(of->kn); - struct kobject *kobj = of->kn->s_parent->priv; + struct kobject *kobj = of->kn->parent->priv; if (!count) return 0; @@ -119,7 +119,7 @@ static ssize_t sysfs_kf_bin_write(struct sysfs_open_file *of, char *buf, size_t count, loff_t pos) { struct bin_attribute *battr = of->kn->priv; - struct kobject *kobj = of->kn->s_parent->priv; + struct kobject *kobj = of->kn->parent->priv; loff_t size = file_inode(of->file)->i_size; if (size) { @@ -140,7 +140,7 @@ static int sysfs_kf_bin_mmap(struct sysfs_open_file *of, struct vm_area_struct *vma) { struct bin_attribute *battr = of->kn->priv; - struct kobject *kobj = of->kn->s_parent->priv; + struct kobject *kobj = of->kn->parent->priv; return battr->mmap(of->file, kobj, battr, vma); } @@ -345,7 +345,7 @@ int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, if (!kn) return -ENOENT; - newattrs.ia_mode = (mode & S_IALLUGO) | (kn->s_mode & ~S_IALLUGO); + newattrs.ia_mode = (mode & S_IALLUGO) | (kn->mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE; rc = kernfs_setattr(kn, &newattrs); diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 4ed3d49ad279..0d48ea911508 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -129,7 +129,7 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, */ spin_lock(&sysfs_symlink_target_lock); if (targ->sd && kernfs_ns_enabled(kobj->sd)) - ns = targ->sd->s_ns; + ns = targ->sd->ns; spin_unlock(&sysfs_symlink_target_lock); kernfs_remove_by_name_ns(kobj->sd, name, ns); } @@ -175,7 +175,7 @@ int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, parent = kobj->sd; if (targ->sd) - old_ns = targ->sd->s_ns; + old_ns = targ->sd->ns; result = -ENOENT; kn = kernfs_find_and_get_ns(parent, old, old_ns); @@ -185,7 +185,7 @@ int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, result = -EINVAL; if (sysfs_type(kn) != SYSFS_KOBJ_LINK) goto out; - if (kn->s_symlink.target_kn->priv != targ) + if (kn->symlink.target_kn->priv != targ) goto out; result = kernfs_rename_ns(kn, parent, new, new_ns); diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 195d1c6a8b0c..092469f60e3e 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -49,7 +49,7 @@ enum kernfs_node_flag { /* type-specific structures for kernfs_node union members */ struct kernfs_elem_dir { unsigned long subdirs; - /* children rbtree starts here and goes through kn->s_rb */ + /* children rbtree starts here and goes through kn->rb */ struct rb_root children; /* @@ -79,36 +79,36 @@ struct kernfs_elem_attr { * active reference. */ struct kernfs_node { - atomic_t s_count; - atomic_t s_active; + atomic_t count; + atomic_t active; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif /* the following two fields are published */ - struct kernfs_node *s_parent; - const char *s_name; + struct kernfs_node *parent; + const char *name; - struct rb_node s_rb; + struct rb_node rb; union { struct completion *completion; struct kernfs_node *removed_list; } u; - const void *s_ns; /* namespace tag */ - unsigned int s_hash; /* ns + name hash */ + const void *ns; /* namespace tag */ + unsigned int hash; /* ns + name hash */ union { - struct kernfs_elem_dir s_dir; - struct kernfs_elem_symlink s_symlink; - struct kernfs_elem_attr s_attr; + struct kernfs_elem_dir dir; + struct kernfs_elem_symlink symlink; + struct kernfs_elem_attr attr; }; void *priv; - unsigned short s_flags; - umode_t s_mode; - unsigned int s_ino; - struct sysfs_inode_attrs *s_iattr; + unsigned short flags; + umode_t mode; + unsigned int ino; + struct sysfs_inode_attrs *iattr; }; struct kernfs_root { @@ -172,7 +172,7 @@ struct kernfs_ops { static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) { - return kn->s_flags & SYSFS_TYPE_MASK; + return kn->flags & SYSFS_TYPE_MASK; } /** @@ -186,8 +186,8 @@ static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) static inline void kernfs_enable_ns(struct kernfs_node *kn) { WARN_ON_ONCE(sysfs_type(kn) != SYSFS_DIR); - WARN_ON_ONCE(!RB_EMPTY_ROOT(&kn->s_dir.children)); - kn->s_flags |= SYSFS_FLAG_NS; + WARN_ON_ONCE(!RB_EMPTY_ROOT(&kn->dir.children)); + kn->flags |= SYSFS_FLAG_NS; } /** @@ -198,7 +198,7 @@ static inline void kernfs_enable_ns(struct kernfs_node *kn) */ static inline bool kernfs_ns_enabled(struct kernfs_node *kn) { - return kn->s_flags & SYSFS_FLAG_NS; + return kn->flags & SYSFS_FLAG_NS; } struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, -- cgit v1.2.3-59-g8ed1b From 2ae77527bb1a510070d039aaa22d1ae9a5807b6f Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 6 Nov 2013 16:58:16 -0700 Subject: clk: tegra: remove legacy reset APIs Now that no code uses the custom Tegra module reset API, we can remove its implementation. Signed-off-by: Stephen Warren Reviewed-by: Thierry Reding Acked-By: Peter De Schrijver --- drivers/clk/tegra/clk-periph-gate.c | 22 -------------------- drivers/clk/tegra/clk-periph.c | 40 ------------------------------------- drivers/clk/tegra/clk.h | 1 - include/linux/clk/tegra.h | 7 ------- 4 files changed, 70 deletions(-) (limited to 'include/linux') diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c index f38f33e3c65d..507015314827 100644 --- a/drivers/clk/tegra/clk-periph-gate.c +++ b/drivers/clk/tegra/clk-periph-gate.c @@ -36,8 +36,6 @@ static DEFINE_SPINLOCK(periph_ref_lock); #define read_rst(gate) \ readl_relaxed(gate->clk_base + (gate->regs->rst_reg)) -#define write_rst_set(val, gate) \ - writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg)) #define write_rst_clr(val, gate) \ writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg)) @@ -123,26 +121,6 @@ static void clk_periph_disable(struct clk_hw *hw) spin_unlock_irqrestore(&periph_ref_lock, flags); } -void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert) -{ - if (gate->flags & TEGRA_PERIPH_NO_RESET) - return; - - if (assert) { - /* - * If peripheral is in the APB bus then read the APB bus to - * flush the write operation in apb bus. This will avoid the - * peripheral access after disabling clock - */ - if (gate->flags & TEGRA_PERIPH_ON_APB) - tegra_read_chipid(); - - write_rst_set(periph_clk_to_bit(gate), gate); - } else { - write_rst_clr(periph_clk_to_bit(gate), gate); - } -} - const struct clk_ops tegra_clk_periph_gate_ops = { .is_enabled = clk_periph_is_enabled, .enable = clk_periph_enable, diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index d62b396863c1..c534043c0481 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -111,46 +111,6 @@ static void clk_periph_disable(struct clk_hw *hw) gate_ops->disable(gate_hw); } -void tegra_periph_reset_deassert(struct clk *c) -{ - struct clk_hw *hw = __clk_get_hw(c); - struct tegra_clk_periph *periph = to_clk_periph(hw); - struct tegra_clk_periph_gate *gate; - - if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) { - gate = to_clk_periph_gate(hw); - if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) { - WARN_ON(1); - return; - } - } else { - gate = &periph->gate; - } - - tegra_periph_reset(gate, 0); -} -EXPORT_SYMBOL(tegra_periph_reset_deassert); - -void tegra_periph_reset_assert(struct clk *c) -{ - struct clk_hw *hw = __clk_get_hw(c); - struct tegra_clk_periph *periph = to_clk_periph(hw); - struct tegra_clk_periph_gate *gate; - - if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) { - gate = to_clk_periph_gate(hw); - if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) { - WARN_ON(1); - return; - } - } else { - gate = &periph->gate; - } - - tegra_periph_reset(gate, 1); -} -EXPORT_SYMBOL(tegra_periph_reset_assert); - const struct clk_ops tegra_clk_periph_ops = { .get_parent = clk_periph_get_parent, .set_parent = clk_periph_set_parent, diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 07c62f997371..16ec8d6bb87f 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -393,7 +393,6 @@ struct tegra_clk_periph_gate { #define TEGRA_PERIPH_NO_DIV BIT(4) #define TEGRA_PERIPH_NO_GATE BIT(5) -void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert); extern const struct clk_ops tegra_clk_periph_gate_ops; struct clk *tegra_clk_register_periph_gate(const char *name, const char *parent_name, u8 gate_flags, void __iomem *clk_base, diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index 23a0ceee831f..3ca9fca827a2 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -120,13 +120,6 @@ static inline void tegra_cpu_clock_resume(void) } #endif -#ifdef CONFIG_ARCH_TEGRA -void tegra_periph_reset_deassert(struct clk *c); -void tegra_periph_reset_assert(struct clk *c); -#else -static inline void tegra_periph_reset_deassert(struct clk *c) {} -static inline void tegra_periph_reset_assert(struct clk *c) {} -#endif void tegra_clocks_apply_init_table(void); #endif /* __LINUX_CLK_TEGRA_H_ */ -- cgit v1.2.3-59-g8ed1b From c525aaddc366df23eb095d58a2bdf11cce62a98b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:55 -0500 Subject: kernfs: s/sysfs/kernfs/ in various data structures kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. This patch performs the following renames. * s/sysfs_open_dirent/kernfs_open_node/ * s/sysfs_open_file/kernfs_open_file/ * s/sysfs_inode_attrs/kernfs_iattrs/ * s/sysfs_addrm_cxt/kernfs_addrm_cxt/ * s/sysfs_super_info/kernfs_super_info/ * s/sysfs_info()/kernfs_info()/ * s/sysfs_open_dirent_lock/kernfs_open_node_lock/ * s/sysfs_open_file_mutex/kernfs_open_file_mutex/ * s/sysfs_of()/kernfs_of()/ This patch is strictly rename only and doesn't introduce any functional difference. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 28 ++++---- fs/kernfs/file.c | 172 ++++++++++++++++++++++---------------------- fs/kernfs/inode.c | 30 ++++---- fs/kernfs/kernfs-internal.h | 20 +++--- fs/kernfs/mount.c | 14 ++-- fs/kernfs/symlink.c | 2 +- fs/sysfs/file.c | 10 +-- include/linux/kernfs.h | 18 ++--- 8 files changed, 147 insertions(+), 147 deletions(-) (limited to 'include/linux') diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 51fff9d2b334..d038bb204b54 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -295,7 +295,7 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) /* The sysfs dirent has been moved to a different namespace */ if (kn->parent && kernfs_ns_enabled(kn->parent) && - sysfs_info(dentry->d_sb)->ns != kn->ns) + kernfs_info(dentry->d_sb)->ns != kn->ns) goto out_bad; mutex_unlock(&sysfs_mutex); @@ -375,7 +375,7 @@ struct kernfs_node *sysfs_new_dirent(struct kernfs_root *root, /** * sysfs_addrm_start - prepare for kernfs_node add/remove - * @acxt: pointer to sysfs_addrm_cxt to be used + * @acxt: pointer to kernfs_addrm_cxt to be used * * This function is called when the caller is about to add or remove * kernfs_node. This function acquires sysfs_mutex. @acxt is used to @@ -385,7 +385,7 @@ struct kernfs_node *sysfs_new_dirent(struct kernfs_root *root, * Kernel thread context (may sleep). sysfs_mutex is locked on * return. */ -void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt) +void sysfs_addrm_start(struct kernfs_addrm_cxt *acxt) __acquires(sysfs_mutex) { memset(acxt, 0, sizeof(*acxt)); @@ -414,11 +414,11 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt) * 0 on success, -EEXIST if entry with the given name already * exists. */ -int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct kernfs_node *kn, +int sysfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn, struct kernfs_node *parent) { bool has_ns = kernfs_ns_enabled(parent); - struct sysfs_inode_attrs *ps_iattr; + struct kernfs_iattrs *ps_iattr; int ret; if (has_ns != (bool)kn->ns) { @@ -466,10 +466,10 @@ int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct kernfs_node *kn, * LOCKING: * Determined by sysfs_addrm_start(). */ -static void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, +static void sysfs_remove_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn) { - struct sysfs_inode_attrs *ps_iattr; + struct kernfs_iattrs *ps_iattr; /* * Removal can be called multiple times on the same node. Only the @@ -505,7 +505,7 @@ static void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, * LOCKING: * sysfs_mutex is released. */ -void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt) +void sysfs_addrm_finish(struct kernfs_addrm_cxt *acxt) __releases(sysfs_mutex) { /* release resources acquired by sysfs_addrm_start() */ @@ -649,7 +649,7 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, const void *ns) { umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; - struct sysfs_addrm_cxt acxt; + struct kernfs_addrm_cxt acxt; struct kernfs_node *kn; int rc; @@ -686,7 +686,7 @@ static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry, mutex_lock(&sysfs_mutex); if (kernfs_ns_enabled(parent)) - ns = sysfs_info(dir->i_sb)->ns; + ns = kernfs_info(dir->i_sb)->ns; kn = kernfs_find_ns(parent, dentry->d_name.name, ns); @@ -778,7 +778,7 @@ static struct kernfs_node *sysfs_next_descendant_post(struct kernfs_node *pos, return pos->parent; } -static void __kernfs_remove(struct sysfs_addrm_cxt *acxt, +static void __kernfs_remove(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn) { struct kernfs_node *pos, *next; @@ -805,7 +805,7 @@ static void __kernfs_remove(struct sysfs_addrm_cxt *acxt, */ void kernfs_remove(struct kernfs_node *kn) { - struct sysfs_addrm_cxt acxt; + struct kernfs_addrm_cxt acxt; sysfs_addrm_start(&acxt); __kernfs_remove(&acxt, kn); @@ -824,7 +824,7 @@ void kernfs_remove(struct kernfs_node *kn) int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, const void *ns) { - struct sysfs_addrm_cxt acxt; + struct kernfs_addrm_cxt acxt; struct kernfs_node *kn; if (!parent) { @@ -971,7 +971,7 @@ static int sysfs_readdir(struct file *file, struct dir_context *ctx) mutex_lock(&sysfs_mutex); if (kernfs_ns_enabled(parent)) - ns = sysfs_info(dentry->d_sb)->ns; + ns = kernfs_info(dentry->d_sb)->ns; for (pos = sysfs_dir_pos(ns, parent, ctx->pos, pos); pos; diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 5277021196a7..2714a394cd81 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -18,27 +18,27 @@ #include "kernfs-internal.h" /* - * There's one sysfs_open_file for each open file and one sysfs_open_dirent + * There's one kernfs_open_file for each open file and one kernfs_open_node * for each kernfs_node with one or more open files. * - * kernfs_node->attr.open points to sysfs_open_dirent. attr.open is - * protected by sysfs_open_dirent_lock. + * kernfs_node->attr.open points to kernfs_open_node. attr.open is + * protected by kernfs_open_node_lock. * * filp->private_data points to seq_file whose ->private points to - * sysfs_open_file. sysfs_open_files are chained at - * sysfs_open_dirent->files, which is protected by sysfs_open_file_mutex. + * kernfs_open_file. kernfs_open_files are chained at + * kernfs_open_node->files, which is protected by kernfs_open_file_mutex. */ -static DEFINE_SPINLOCK(sysfs_open_dirent_lock); -static DEFINE_MUTEX(sysfs_open_file_mutex); +static DEFINE_SPINLOCK(kernfs_open_node_lock); +static DEFINE_MUTEX(kernfs_open_file_mutex); -struct sysfs_open_dirent { +struct kernfs_open_node { atomic_t refcnt; atomic_t event; wait_queue_head_t poll; - struct list_head files; /* goes through sysfs_open_file.list */ + struct list_head files; /* goes through kernfs_open_file.list */ }; -static struct sysfs_open_file *sysfs_of(struct file *file) +static struct kernfs_open_file *kernfs_of(struct file *file) { return ((struct seq_file *)file->private_data)->private; } @@ -56,7 +56,7 @@ static const struct kernfs_ops *kernfs_ops(struct kernfs_node *kn) static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) { - struct sysfs_open_file *of = sf->private; + struct kernfs_open_file *of = sf->private; const struct kernfs_ops *ops; /* @@ -81,7 +81,7 @@ static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) { - struct sysfs_open_file *of = sf->private; + struct kernfs_open_file *of = sf->private; const struct kernfs_ops *ops = kernfs_ops(of->kn); if (ops->seq_next) { @@ -98,7 +98,7 @@ static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) static void kernfs_seq_stop(struct seq_file *sf, void *v) { - struct sysfs_open_file *of = sf->private; + struct kernfs_open_file *of = sf->private; const struct kernfs_ops *ops = kernfs_ops(of->kn); if (ops->seq_stop) @@ -110,7 +110,7 @@ static void kernfs_seq_stop(struct seq_file *sf, void *v) static int kernfs_seq_show(struct seq_file *sf, void *v) { - struct sysfs_open_file *of = sf->private; + struct kernfs_open_file *of = sf->private; of->event = atomic_read(&of->kn->attr.open->event); @@ -130,7 +130,7 @@ static const struct seq_operations kernfs_seq_ops = { * it difficult to use seq_file. Implement simplistic custom buffering for * bin files. */ -static ssize_t kernfs_file_direct_read(struct sysfs_open_file *of, +static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of, char __user *user_buf, size_t count, loff_t *ppos) { @@ -187,7 +187,7 @@ static ssize_t kernfs_file_direct_read(struct sysfs_open_file *of, static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); if (of->kn->flags & SYSFS_FLAG_HAS_SEQ_SHOW) return seq_read(file, user_buf, count, ppos); @@ -214,7 +214,7 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, static ssize_t kernfs_file_write(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); ssize_t len = min_t(size_t, count, PAGE_SIZE); const struct kernfs_ops *ops; char *buf; @@ -259,7 +259,7 @@ out_free: static void kernfs_vma_open(struct vm_area_struct *vma) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); if (!of->vm_ops) return; @@ -276,7 +276,7 @@ static void kernfs_vma_open(struct vm_area_struct *vma) static int kernfs_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); int ret; if (!of->vm_ops) @@ -297,7 +297,7 @@ static int kernfs_vma_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); int ret; if (!of->vm_ops) @@ -320,7 +320,7 @@ static int kernfs_vma_access(struct vm_area_struct *vma, unsigned long addr, void *buf, int len, int write) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); int ret; if (!of->vm_ops) @@ -342,7 +342,7 @@ static int kernfs_vma_set_policy(struct vm_area_struct *vma, struct mempolicy *new) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); int ret; if (!of->vm_ops) @@ -363,7 +363,7 @@ static struct mempolicy *kernfs_vma_get_policy(struct vm_area_struct *vma, unsigned long addr) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); struct mempolicy *pol; if (!of->vm_ops) @@ -385,7 +385,7 @@ static int kernfs_vma_migrate(struct vm_area_struct *vma, unsigned long flags) { struct file *file = vma->vm_file; - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); int ret; if (!of->vm_ops) @@ -417,7 +417,7 @@ static const struct vm_operations_struct kernfs_vm_ops = { static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) { - struct sysfs_open_file *of = sysfs_of(file); + struct kernfs_open_file *of = kernfs_of(file); const struct kernfs_ops *ops; int rc; @@ -473,9 +473,9 @@ out_unlock: } /** - * sysfs_get_open_dirent - get or create sysfs_open_dirent + * sysfs_get_open_dirent - get or create kernfs_open_node * @kn: target kernfs_node - * @of: sysfs_open_file for this instance of open + * @of: kernfs_open_file for this instance of open * * If @kn->attr.open exists, increment its reference count; otherwise, * create one. @of is chained to the files list. @@ -487,49 +487,49 @@ out_unlock: * 0 on success, -errno on failure. */ static int sysfs_get_open_dirent(struct kernfs_node *kn, - struct sysfs_open_file *of) + struct kernfs_open_file *of) { - struct sysfs_open_dirent *od, *new_od = NULL; + struct kernfs_open_node *on, *new_on = NULL; retry: - mutex_lock(&sysfs_open_file_mutex); - spin_lock_irq(&sysfs_open_dirent_lock); + mutex_lock(&kernfs_open_file_mutex); + spin_lock_irq(&kernfs_open_node_lock); - if (!kn->attr.open && new_od) { - kn->attr.open = new_od; - new_od = NULL; + if (!kn->attr.open && new_on) { + kn->attr.open = new_on; + new_on = NULL; } - od = kn->attr.open; - if (od) { - atomic_inc(&od->refcnt); - list_add_tail(&of->list, &od->files); + on = kn->attr.open; + if (on) { + atomic_inc(&on->refcnt); + list_add_tail(&of->list, &on->files); } - spin_unlock_irq(&sysfs_open_dirent_lock); - mutex_unlock(&sysfs_open_file_mutex); + spin_unlock_irq(&kernfs_open_node_lock); + mutex_unlock(&kernfs_open_file_mutex); - if (od) { - kfree(new_od); + if (on) { + kfree(new_on); return 0; } /* not there, initialize a new one and retry */ - new_od = kmalloc(sizeof(*new_od), GFP_KERNEL); - if (!new_od) + new_on = kmalloc(sizeof(*new_on), GFP_KERNEL); + if (!new_on) return -ENOMEM; - atomic_set(&new_od->refcnt, 0); - atomic_set(&new_od->event, 1); - init_waitqueue_head(&new_od->poll); - INIT_LIST_HEAD(&new_od->files); + atomic_set(&new_on->refcnt, 0); + atomic_set(&new_on->event, 1); + init_waitqueue_head(&new_on->poll); + INIT_LIST_HEAD(&new_on->files); goto retry; } /** - * sysfs_put_open_dirent - put sysfs_open_dirent + * sysfs_put_open_dirent - put kernfs_open_node * @kn: target kernfs_nodet - * @of: associated sysfs_open_file + * @of: associated kernfs_open_file * * Put @kn->attr.open and unlink @of from the files list. If * reference count reaches zero, disassociate and free it. @@ -538,33 +538,33 @@ static int sysfs_get_open_dirent(struct kernfs_node *kn, * None. */ static void sysfs_put_open_dirent(struct kernfs_node *kn, - struct sysfs_open_file *of) + struct kernfs_open_file *of) { - struct sysfs_open_dirent *od = kn->attr.open; + struct kernfs_open_node *on = kn->attr.open; unsigned long flags; - mutex_lock(&sysfs_open_file_mutex); - spin_lock_irqsave(&sysfs_open_dirent_lock, flags); + mutex_lock(&kernfs_open_file_mutex); + spin_lock_irqsave(&kernfs_open_node_lock, flags); if (of) list_del(&of->list); - if (atomic_dec_and_test(&od->refcnt)) + if (atomic_dec_and_test(&on->refcnt)) kn->attr.open = NULL; else - od = NULL; + on = NULL; - spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags); - mutex_unlock(&sysfs_open_file_mutex); + spin_unlock_irqrestore(&kernfs_open_node_lock, flags); + mutex_unlock(&kernfs_open_file_mutex); - kfree(od); + kfree(on); } static int kernfs_file_open(struct inode *inode, struct file *file) { struct kernfs_node *kn = file->f_path.dentry->d_fsdata; const struct kernfs_ops *ops; - struct sysfs_open_file *of; + struct kernfs_open_file *of; bool has_read, has_write, has_mmap; int error = -EACCES; @@ -586,9 +586,9 @@ static int kernfs_file_open(struct inode *inode, struct file *file) (!(inode->i_mode & S_IRUGO) || !has_read)) goto err_out; - /* allocate a sysfs_open_file for the file */ + /* allocate a kernfs_open_file for the file */ error = -ENOMEM; - of = kzalloc(sizeof(struct sysfs_open_file), GFP_KERNEL); + of = kzalloc(sizeof(struct kernfs_open_file), GFP_KERNEL); if (!of) goto err_out; @@ -654,7 +654,7 @@ err_out: static int kernfs_file_release(struct inode *inode, struct file *filp) { struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; - struct sysfs_open_file *of = sysfs_of(filp); + struct kernfs_open_file *of = kernfs_of(filp); sysfs_put_open_dirent(kn, of); seq_release(inode, filp); @@ -665,26 +665,26 @@ static int kernfs_file_release(struct inode *inode, struct file *filp) void sysfs_unmap_bin_file(struct kernfs_node *kn) { - struct sysfs_open_dirent *od; - struct sysfs_open_file *of; + struct kernfs_open_node *on; + struct kernfs_open_file *of; if (!(kn->flags & SYSFS_FLAG_HAS_MMAP)) return; - spin_lock_irq(&sysfs_open_dirent_lock); - od = kn->attr.open; - if (od) - atomic_inc(&od->refcnt); - spin_unlock_irq(&sysfs_open_dirent_lock); - if (!od) + spin_lock_irq(&kernfs_open_node_lock); + on = kn->attr.open; + if (on) + atomic_inc(&on->refcnt); + spin_unlock_irq(&kernfs_open_node_lock); + if (!on) return; - mutex_lock(&sysfs_open_file_mutex); - list_for_each_entry(of, &od->files, list) { + mutex_lock(&kernfs_open_file_mutex); + list_for_each_entry(of, &on->files, list) { struct inode *inode = file_inode(of->file); unmap_mapping_range(inode->i_mapping, 0, 0, 1); } - mutex_unlock(&sysfs_open_file_mutex); + mutex_unlock(&kernfs_open_file_mutex); sysfs_put_open_dirent(kn, NULL); } @@ -704,19 +704,19 @@ void sysfs_unmap_bin_file(struct kernfs_node *kn) */ static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) { - struct sysfs_open_file *of = sysfs_of(filp); + struct kernfs_open_file *of = kernfs_of(filp); struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; - struct sysfs_open_dirent *od = kn->attr.open; + struct kernfs_open_node *on = kn->attr.open; /* need parent for the kobj, grab both */ if (!sysfs_get_active(kn)) goto trigger; - poll_wait(filp, &od->poll, wait); + poll_wait(filp, &on->poll, wait); sysfs_put_active(kn); - if (of->event != atomic_read(&od->event)) + if (of->event != atomic_read(&on->event)) goto trigger; return DEFAULT_POLLMASK; @@ -733,20 +733,20 @@ static unsigned int kernfs_file_poll(struct file *filp, poll_table *wait) */ void kernfs_notify(struct kernfs_node *kn) { - struct sysfs_open_dirent *od; + struct kernfs_open_node *on; unsigned long flags; - spin_lock_irqsave(&sysfs_open_dirent_lock, flags); + spin_lock_irqsave(&kernfs_open_node_lock, flags); if (!WARN_ON(sysfs_type(kn) != SYSFS_KOBJ_ATTR)) { - od = kn->attr.open; - if (od) { - atomic_inc(&od->event); - wake_up_interruptible(&od->poll); + on = kn->attr.open; + if (on) { + atomic_inc(&on->event); + wake_up_interruptible(&on->poll); } } - spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags); + spin_unlock_irqrestore(&kernfs_open_node_lock, flags); } EXPORT_SYMBOL_GPL(kernfs_notify); @@ -780,7 +780,7 @@ struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, void *priv, const void *ns, struct lock_class_key *key) { - struct sysfs_addrm_cxt acxt; + struct kernfs_addrm_cxt acxt; struct kernfs_node *kn; int rc; diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index f6c0aae3dd5c..a0e0038fd570 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -46,14 +46,14 @@ void __init sysfs_inode_init(void) panic("failed to init sysfs_backing_dev_info"); } -static struct sysfs_inode_attrs *sysfs_inode_attrs(struct kernfs_node *kn) +static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn) { struct iattr *iattrs; if (kn->iattr) return kn->iattr; - kn->iattr = kzalloc(sizeof(struct sysfs_inode_attrs), GFP_KERNEL); + kn->iattr = kzalloc(sizeof(struct kernfs_iattrs), GFP_KERNEL); if (!kn->iattr) return NULL; iattrs = &kn->iattr->ia_iattr; @@ -71,11 +71,11 @@ static struct sysfs_inode_attrs *sysfs_inode_attrs(struct kernfs_node *kn) static int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) { - struct sysfs_inode_attrs *attrs; + struct kernfs_iattrs *attrs; struct iattr *iattrs; unsigned int ia_valid = iattr->ia_valid; - attrs = sysfs_inode_attrs(kn); + attrs = kernfs_iattrs(kn); if (!attrs) return -ENOMEM; @@ -144,11 +144,11 @@ out: static int sysfs_sd_setsecdata(struct kernfs_node *kn, void **secdata, u32 *secdata_len) { - struct sysfs_inode_attrs *attrs; + struct kernfs_iattrs *attrs; void *old_secdata; size_t old_secdata_len; - attrs = sysfs_inode_attrs(kn); + attrs = kernfs_iattrs(kn); if (!attrs) return -ENOMEM; @@ -167,12 +167,12 @@ int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct kernfs_node *kn = dentry->d_fsdata; - struct sysfs_inode_attrs *attrs; + struct kernfs_iattrs *attrs; void *secdata; int error; u32 secdata_len = 0; - attrs = sysfs_inode_attrs(kn); + attrs = kernfs_iattrs(kn); if (!attrs) return -ENOMEM; @@ -205,9 +205,9 @@ int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, int sysfs_removexattr(struct dentry *dentry, const char *name) { struct kernfs_node *kn = dentry->d_fsdata; - struct sysfs_inode_attrs *attrs; + struct kernfs_iattrs *attrs; - attrs = sysfs_inode_attrs(kn); + attrs = kernfs_iattrs(kn); if (!attrs) return -ENOMEM; @@ -218,9 +218,9 @@ ssize_t sysfs_getxattr(struct dentry *dentry, const char *name, void *buf, size_t size) { struct kernfs_node *kn = dentry->d_fsdata; - struct sysfs_inode_attrs *attrs; + struct kernfs_iattrs *attrs; - attrs = sysfs_inode_attrs(kn); + attrs = kernfs_iattrs(kn); if (!attrs) return -ENOMEM; @@ -230,9 +230,9 @@ ssize_t sysfs_getxattr(struct dentry *dentry, const char *name, void *buf, ssize_t sysfs_listxattr(struct dentry *dentry, char *buf, size_t size) { struct kernfs_node *kn = dentry->d_fsdata; - struct sysfs_inode_attrs *attrs; + struct kernfs_iattrs *attrs; - attrs = sysfs_inode_attrs(kn); + attrs = kernfs_iattrs(kn); if (!attrs) return -ENOMEM; @@ -256,7 +256,7 @@ static inline void set_inode_attr(struct inode *inode, struct iattr *iattr) static void sysfs_refresh_inode(struct kernfs_node *kn, struct inode *inode) { - struct sysfs_inode_attrs *attrs = kn->iattr; + struct kernfs_iattrs *attrs = kn->iattr; inode->i_mode = kn->mode; if (attrs) { diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 2dbb1cb95e7f..573f66988643 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -18,7 +18,7 @@ #include -struct sysfs_inode_attrs { +struct kernfs_iattrs { struct iattr ia_iattr; void *ia_secdata; u32 ia_secdata_len; @@ -47,14 +47,14 @@ static inline struct kernfs_root *kernfs_root(struct kernfs_node *kn) /* * Context structure to be used while adding/removing nodes. */ -struct sysfs_addrm_cxt { +struct kernfs_addrm_cxt { struct kernfs_node *removed; }; /* * mount.c */ -struct sysfs_super_info { +struct kernfs_super_info { /* * The root associated with this super_block. Each super_block is * identified by the root and ns it's associated with. @@ -63,13 +63,13 @@ struct sysfs_super_info { /* * Each sb is associated with one namespace tag, currently the - * network namespace of the task which mounted this sysfs instance. - * If multiple tags become necessary, make the following an array - * and compare kernfs_node tag against every entry. + * network namespace of the task which mounted this kernfs + * instance. If multiple tags become necessary, make the following + * an array and compare kernfs_node tag against every entry. */ const void *ns; }; -#define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) +#define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info)) extern struct kmem_cache *sysfs_dir_cachep; @@ -100,10 +100,10 @@ extern const struct inode_operations sysfs_dir_inode_operations; struct kernfs_node *sysfs_get_active(struct kernfs_node *kn); void sysfs_put_active(struct kernfs_node *kn); -void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt); -int sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct kernfs_node *kn, +void sysfs_addrm_start(struct kernfs_addrm_cxt *acxt); +int sysfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn, struct kernfs_node *parent); -void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); +void sysfs_addrm_finish(struct kernfs_addrm_cxt *acxt); struct kernfs_node *sysfs_new_dirent(struct kernfs_root *root, const char *name, umode_t mode, int type); diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 9dbbf37b1af9..e0796dcb6065 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -27,7 +27,7 @@ static const struct super_operations sysfs_ops = { static int sysfs_fill_super(struct super_block *sb) { - struct sysfs_super_info *info = sysfs_info(sb); + struct kernfs_super_info *info = kernfs_info(sb); struct inode *inode; struct dentry *root; @@ -61,8 +61,8 @@ static int sysfs_fill_super(struct super_block *sb) static int sysfs_test_super(struct super_block *sb, void *data) { - struct sysfs_super_info *sb_info = sysfs_info(sb); - struct sysfs_super_info *info = data; + struct kernfs_super_info *sb_info = kernfs_info(sb); + struct kernfs_super_info *info = data; return sb_info->root == info->root && sb_info->ns == info->ns; } @@ -84,7 +84,7 @@ static int sysfs_set_super(struct super_block *sb, void *data) */ const void *kernfs_super_ns(struct super_block *sb) { - struct sysfs_super_info *info = sysfs_info(sb); + struct kernfs_super_info *info = kernfs_info(sb); return info->ns; } @@ -107,7 +107,7 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, struct kernfs_root *root, const void *ns) { struct super_block *sb; - struct sysfs_super_info *info; + struct kernfs_super_info *info; int error; info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -144,12 +144,12 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, */ void kernfs_kill_sb(struct super_block *sb) { - struct sysfs_super_info *info = sysfs_info(sb); + struct kernfs_super_info *info = kernfs_info(sb); struct kernfs_node *root_kn = sb->s_root->d_fsdata; /* * Remove the superblock from fs_supers/s_instances - * so we can't find it, before freeing sysfs_super_info. + * so we can't find it, before freeing kernfs_super_info. */ kill_anon_super(sb); kfree(info); diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index 5ac1a57c3807..f36e3f1b2477 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -27,7 +27,7 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, struct kernfs_node *target) { struct kernfs_node *kn; - struct sysfs_addrm_cxt acxt; + struct kernfs_addrm_cxt acxt; int error; kn = sysfs_new_dirent(kernfs_root(parent), name, S_IFLNK|S_IRWXUGO, diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 887703a79065..fd104b282f81 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -41,7 +41,7 @@ static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn) */ static int sysfs_kf_seq_show(struct seq_file *sf, void *v) { - struct sysfs_open_file *of = sf->private; + struct kernfs_open_file *of = sf->private; struct kobject *kobj = of->kn->parent->priv; const struct sysfs_ops *ops = sysfs_file_ops(of->kn); ssize_t count; @@ -78,7 +78,7 @@ static int sysfs_kf_seq_show(struct seq_file *sf, void *v) return 0; } -static ssize_t sysfs_kf_bin_read(struct sysfs_open_file *of, char *buf, +static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf, size_t count, loff_t pos) { struct bin_attribute *battr = of->kn->priv; @@ -102,7 +102,7 @@ static ssize_t sysfs_kf_bin_read(struct sysfs_open_file *of, char *buf, } /* kernfs write callback for regular sysfs files */ -static ssize_t sysfs_kf_write(struct sysfs_open_file *of, char *buf, +static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf, size_t count, loff_t pos) { const struct sysfs_ops *ops = sysfs_file_ops(of->kn); @@ -115,7 +115,7 @@ static ssize_t sysfs_kf_write(struct sysfs_open_file *of, char *buf, } /* kernfs write callback for bin sysfs files */ -static ssize_t sysfs_kf_bin_write(struct sysfs_open_file *of, char *buf, +static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf, size_t count, loff_t pos) { struct bin_attribute *battr = of->kn->priv; @@ -136,7 +136,7 @@ static ssize_t sysfs_kf_bin_write(struct sysfs_open_file *of, char *buf, return battr->write(of->file, kobj, battr, buf, pos, count); } -static int sysfs_kf_bin_mmap(struct sysfs_open_file *of, +static int sysfs_kf_bin_mmap(struct kernfs_open_file *of, struct vm_area_struct *vma) { struct bin_attribute *battr = of->kn->priv; diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 092469f60e3e..757647c4cb3b 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -24,8 +24,8 @@ struct vm_area_struct; struct super_block; struct file_system_type; -struct sysfs_open_dirent; -struct sysfs_inode_attrs; +struct kernfs_open_node; +struct kernfs_iattrs; enum kernfs_node_type { SYSFS_DIR = 0x0001, @@ -65,7 +65,7 @@ struct kernfs_elem_symlink { struct kernfs_elem_attr { const struct kernfs_ops *ops; - struct sysfs_open_dirent *open; + struct kernfs_open_node *open; loff_t size; }; @@ -108,7 +108,7 @@ struct kernfs_node { unsigned short flags; umode_t mode; unsigned int ino; - struct sysfs_inode_attrs *iattr; + struct kernfs_iattrs *iattr; }; struct kernfs_root { @@ -119,7 +119,7 @@ struct kernfs_root { struct ida ino_ida; }; -struct sysfs_open_file { +struct kernfs_open_file { /* published fields */ struct kernfs_node *kn; struct file *file; @@ -140,7 +140,7 @@ struct kernfs_ops { * If seq_show() is present, seq_file path is active. Other seq * operations are optional and if not implemented, the behavior is * equivalent to single_open(). @sf->private points to the - * associated sysfs_open_file. + * associated kernfs_open_file. * * read() is bounced through kernel buffer and a read larger than * PAGE_SIZE results in partial operation of PAGE_SIZE. @@ -151,17 +151,17 @@ struct kernfs_ops { void *(*seq_next)(struct seq_file *sf, void *v, loff_t *ppos); void (*seq_stop)(struct seq_file *sf, void *v); - ssize_t (*read)(struct sysfs_open_file *of, char *buf, size_t bytes, + ssize_t (*read)(struct kernfs_open_file *of, char *buf, size_t bytes, loff_t off); /* * write() is bounced through kernel buffer and a write larger than * PAGE_SIZE results in partial operation of PAGE_SIZE. */ - ssize_t (*write)(struct sysfs_open_file *of, char *buf, size_t bytes, + ssize_t (*write)(struct kernfs_open_file *of, char *buf, size_t bytes, loff_t off); - int (*mmap)(struct sysfs_open_file *of, struct vm_area_struct *vma); + int (*mmap)(struct kernfs_open_file *of, struct vm_area_struct *vma); #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lock_class_key lockdep_key; -- cgit v1.2.3-59-g8ed1b From df23fc39bce03bb26e63bea57fc5f5bf6882d74b Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 14:11:56 -0500 Subject: kernfs: s/sysfs/kernfs/ in constants kernfs has just been separated out from sysfs and we're already in full conflict mode. Nothing can make the situation any worse. Let's take the chance to name things properly. This patch performs the following renames. * s/SYSFS_DIR/KERNFS_DIR/ * s/SYSFS_KOBJ_ATTR/KERNFS_FILE/ * s/SYSFS_KOBJ_LINK/KERNFS_LINK/ * s/SYSFS_{TYPE_FLAGS}/KERNFS_{TYPE_FLAGS}/ * s/SYSFS_FLAG_{FLAG}/KERNFS_{FLAG}/ * s/sysfs_type()/kernfs_type()/ * s/SD_DEACTIVATED_BIAS/KN_DEACTIVATED_BIAS/ This patch is strictly rename only and doesn't introduce any functional difference. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 50 ++++++++++++++++++++++----------------------- fs/kernfs/file.c | 18 ++++++++-------- fs/kernfs/inode.c | 10 ++++----- fs/kernfs/kernfs-internal.h | 4 ++-- fs/kernfs/symlink.c | 2 +- fs/sysfs/dir.c | 2 +- fs/sysfs/file.c | 2 +- fs/sysfs/symlink.c | 2 +- include/linux/kernfs.h | 36 ++++++++++++++++---------------- 9 files changed, 63 insertions(+), 63 deletions(-) (limited to 'include/linux') diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index d038bb204b54..bc8a3b367a8c 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -78,7 +78,7 @@ static int sysfs_link_sibling(struct kernfs_node *kn) struct rb_node **node = &kn->parent->dir.children.rb_node; struct rb_node *parent = NULL; - if (sysfs_type(kn) == SYSFS_DIR) + if (kernfs_type(kn) == KERNFS_DIR) kn->parent->dir.subdirs++; while (*node) { @@ -113,7 +113,7 @@ static int sysfs_link_sibling(struct kernfs_node *kn) */ static void sysfs_unlink_sibling(struct kernfs_node *kn) { - if (sysfs_type(kn) == SYSFS_DIR) + if (kernfs_type(kn) == KERNFS_DIR) kn->parent->dir.subdirs--; rb_erase(&kn->rb, &kn->parent->dir.children); @@ -137,7 +137,7 @@ struct kernfs_node *sysfs_get_active(struct kernfs_node *kn) if (!atomic_inc_unless_negative(&kn->active)) return NULL; - if (kn->flags & SYSFS_FLAG_LOCKDEP) + if (kn->flags & KERNFS_LOCKDEP) rwsem_acquire_read(&kn->dep_map, 0, 1, _RET_IP_); return kn; } @@ -156,10 +156,10 @@ void sysfs_put_active(struct kernfs_node *kn) if (unlikely(!kn)) return; - if (kn->flags & SYSFS_FLAG_LOCKDEP) + if (kn->flags & KERNFS_LOCKDEP) rwsem_release(&kn->dep_map, 1, _RET_IP_); v = atomic_dec_return(&kn->active); - if (likely(v != SD_DEACTIVATED_BIAS)) + if (likely(v != KN_DEACTIVATED_BIAS)) return; /* @@ -180,9 +180,9 @@ static void sysfs_deactivate(struct kernfs_node *kn) DECLARE_COMPLETION_ONSTACK(wait); int v; - BUG_ON(!(kn->flags & SYSFS_FLAG_REMOVED)); + BUG_ON(!(kn->flags & KERNFS_REMOVED)); - if (!(sysfs_type(kn) & SYSFS_ACTIVE_REF)) + if (!(kernfs_type(kn) & KERNFS_ACTIVE_REF)) return; kn->u.completion = (void *)&wait; @@ -191,9 +191,9 @@ static void sysfs_deactivate(struct kernfs_node *kn) /* atomic_add_return() is a mb(), put_active() will always see * the updated kn->u.completion. */ - v = atomic_add_return(SD_DEACTIVATED_BIAS, &kn->active); + v = atomic_add_return(KN_DEACTIVATED_BIAS, &kn->active); - if (v != SD_DEACTIVATED_BIAS) { + if (v != KN_DEACTIVATED_BIAS) { lock_contended(&kn->dep_map, _RET_IP_); wait_for_completion(&wait); } @@ -235,13 +235,13 @@ void kernfs_put(struct kernfs_node *kn) */ parent = kn->parent; - WARN(!(kn->flags & SYSFS_FLAG_REMOVED), + WARN(!(kn->flags & KERNFS_REMOVED), "sysfs: free using entry: %s/%s\n", parent ? parent->name : "", kn->name); - if (sysfs_type(kn) == SYSFS_KOBJ_LINK) + if (kernfs_type(kn) == KERNFS_LINK) kernfs_put(kn->symlink.target_kn); - if (sysfs_type(kn) & SYSFS_COPY_NAME) + if (kernfs_type(kn) & KERNFS_COPY_NAME) kfree(kn->name); if (kn->iattr) { if (kn->iattr->ia_secdata) @@ -268,7 +268,7 @@ EXPORT_SYMBOL_GPL(kernfs_put); static int sysfs_dentry_delete(const struct dentry *dentry) { struct kernfs_node *kn = dentry->d_fsdata; - return !(kn && !(kn->flags & SYSFS_FLAG_REMOVED)); + return !(kn && !(kn->flags & KERNFS_REMOVED)); } static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) @@ -282,7 +282,7 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) mutex_lock(&sysfs_mutex); /* The sysfs dirent has been deleted */ - if (kn->flags & SYSFS_FLAG_REMOVED) + if (kn->flags & KERNFS_REMOVED) goto out_bad; /* The sysfs dirent has been moved? */ @@ -342,7 +342,7 @@ struct kernfs_node *sysfs_new_dirent(struct kernfs_root *root, struct kernfs_node *kn; int ret; - if (type & SYSFS_COPY_NAME) { + if (type & KERNFS_COPY_NAME) { name = dup_name = kstrdup(name, GFP_KERNEL); if (!name) return NULL; @@ -362,7 +362,7 @@ struct kernfs_node *sysfs_new_dirent(struct kernfs_root *root, kn->name = name; kn->mode = mode; - kn->flags = type | SYSFS_FLAG_REMOVED; + kn->flags = type | KERNFS_REMOVED; return kn; @@ -427,7 +427,7 @@ int sysfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn, return -EINVAL; } - if (sysfs_type(parent) != SYSFS_DIR) + if (kernfs_type(parent) != KERNFS_DIR) return -EINVAL; kn->hash = sysfs_name_hash(kn->name, kn->ns); @@ -446,7 +446,7 @@ int sysfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn, } /* Mark the entry added into directory tree */ - kn->flags &= ~SYSFS_FLAG_REMOVED; + kn->flags &= ~KERNFS_REMOVED; return 0; } @@ -475,7 +475,7 @@ static void sysfs_remove_one(struct kernfs_addrm_cxt *acxt, * Removal can be called multiple times on the same node. Only the * first invocation is effective and puts the base ref. */ - if (kn->flags & SYSFS_FLAG_REMOVED) + if (kn->flags & KERNFS_REMOVED) return; if (kn->parent) { @@ -489,7 +489,7 @@ static void sysfs_remove_one(struct kernfs_addrm_cxt *acxt, } } - kn->flags |= SYSFS_FLAG_REMOVED; + kn->flags |= KERNFS_REMOVED; kn->u.removed_list = acxt->removed; acxt->removed = kn; } @@ -607,14 +607,14 @@ struct kernfs_root *kernfs_create_root(void *priv) ida_init(&root->ino_ida); - kn = sysfs_new_dirent(root, "", S_IFDIR | S_IRUGO | S_IXUGO, SYSFS_DIR); + kn = sysfs_new_dirent(root, "", S_IFDIR | S_IRUGO | S_IXUGO, KERNFS_DIR); if (!kn) { ida_destroy(&root->ino_ida); kfree(root); return ERR_PTR(-ENOMEM); } - kn->flags &= ~SYSFS_FLAG_REMOVED; + kn->flags &= ~KERNFS_REMOVED; kn->priv = priv; kn->dir.root = root; @@ -654,7 +654,7 @@ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, int rc; /* allocate */ - kn = sysfs_new_dirent(kernfs_root(parent), name, mode, SYSFS_DIR); + kn = sysfs_new_dirent(kernfs_root(parent), name, mode, KERNFS_DIR); if (!kn) return ERR_PTR(-ENOMEM); @@ -732,7 +732,7 @@ static struct kernfs_node *sysfs_leftmost_descendant(struct kernfs_node *pos) last = pos; - if (sysfs_type(pos) != SYSFS_DIR) + if (kernfs_type(pos) != KERNFS_DIR) break; rbn = rb_first(&pos->dir.children); @@ -914,7 +914,7 @@ static struct kernfs_node *sysfs_dir_pos(const void *ns, struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos) { if (pos) { - int valid = !(pos->flags & SYSFS_FLAG_REMOVED) && + int valid = !(pos->flags & KERNFS_REMOVED) && pos->parent == parent && hash == pos->hash; kernfs_put(pos); if (!valid) diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 2714a394cd81..abe93e12089c 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -49,7 +49,7 @@ static struct kernfs_open_file *kernfs_of(struct file *file) */ static const struct kernfs_ops *kernfs_ops(struct kernfs_node *kn) { - if (kn->flags & SYSFS_FLAG_LOCKDEP) + if (kn->flags & KERNFS_LOCKDEP) lockdep_assert_held(kn); return kn->attr.ops; } @@ -189,7 +189,7 @@ static ssize_t kernfs_file_read(struct file *file, char __user *user_buf, { struct kernfs_open_file *of = kernfs_of(file); - if (of->kn->flags & SYSFS_FLAG_HAS_SEQ_SHOW) + if (of->kn->flags & KERNFS_HAS_SEQ_SHOW) return seq_read(file, user_buf, count, ppos); else return kernfs_file_direct_read(of, user_buf, count, ppos); @@ -428,7 +428,7 @@ static int kernfs_file_mmap(struct file *file, struct vm_area_struct *vma) * without grabbing @of->mutex by testing HAS_MMAP flag. See the * comment in kernfs_file_open() for more details. */ - if (!(of->kn->flags & SYSFS_FLAG_HAS_MMAP)) + if (!(of->kn->flags & KERNFS_HAS_MMAP)) return -ENODEV; mutex_lock(&of->mutex); @@ -668,7 +668,7 @@ void sysfs_unmap_bin_file(struct kernfs_node *kn) struct kernfs_open_node *on; struct kernfs_open_file *of; - if (!(kn->flags & SYSFS_FLAG_HAS_MMAP)) + if (!(kn->flags & KERNFS_HAS_MMAP)) return; spin_lock_irq(&kernfs_open_node_lock); @@ -738,7 +738,7 @@ void kernfs_notify(struct kernfs_node *kn) spin_lock_irqsave(&kernfs_open_node_lock, flags); - if (!WARN_ON(sysfs_type(kn) != SYSFS_KOBJ_ATTR)) { + if (!WARN_ON(kernfs_type(kn) != KERNFS_FILE)) { on = kn->attr.open; if (on) { atomic_inc(&on->event); @@ -785,7 +785,7 @@ struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, int rc; kn = sysfs_new_dirent(kernfs_root(parent), name, - (mode & S_IALLUGO) | S_IFREG, SYSFS_KOBJ_ATTR); + (mode & S_IALLUGO) | S_IFREG, KERNFS_FILE); if (!kn) return ERR_PTR(-ENOMEM); @@ -797,7 +797,7 @@ struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, #ifdef CONFIG_DEBUG_LOCK_ALLOC if (key) { lockdep_init_map(&kn->dep_map, "s_active", key, 0); - kn->flags |= SYSFS_FLAG_LOCKDEP; + kn->flags |= KERNFS_LOCKDEP; } #endif @@ -807,9 +807,9 @@ struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, * ref. Cache their existence in flags. */ if (ops->seq_show) - kn->flags |= SYSFS_FLAG_HAS_SEQ_SHOW; + kn->flags |= KERNFS_HAS_SEQ_SHOW; if (ops->mmap) - kn->flags |= SYSFS_FLAG_HAS_MMAP; + kn->flags |= KERNFS_HAS_MMAP; sysfs_addrm_start(&acxt); rc = sysfs_add_one(&acxt, kn, parent); diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c index a0e0038fd570..af92638d792b 100644 --- a/fs/kernfs/inode.c +++ b/fs/kernfs/inode.c @@ -269,7 +269,7 @@ static void sysfs_refresh_inode(struct kernfs_node *kn, struct inode *inode) attrs->ia_secdata_len); } - if (sysfs_type(kn) == SYSFS_DIR) + if (kernfs_type(kn) == KERNFS_DIR) set_nlink(inode, kn->dir.subdirs + 2); } @@ -299,16 +299,16 @@ static void sysfs_init_inode(struct kernfs_node *kn, struct inode *inode) sysfs_refresh_inode(kn, inode); /* initialize inode according to type */ - switch (sysfs_type(kn)) { - case SYSFS_DIR: + switch (kernfs_type(kn)) { + case KERNFS_DIR: inode->i_op = &sysfs_dir_inode_operations; inode->i_fop = &sysfs_dir_operations; break; - case SYSFS_KOBJ_ATTR: + case KERNFS_FILE: inode->i_size = kn->attr.size; inode->i_fop = &kernfs_file_operations; break; - case SYSFS_KOBJ_LINK: + case KERNFS_LINK: inode->i_op = &sysfs_symlink_inode_operations; break; default: diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index 573f66988643..c4bf5bf72f78 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -26,9 +26,9 @@ struct kernfs_iattrs { struct simple_xattrs xattrs; }; -#define SD_DEACTIVATED_BIAS INT_MIN +#define KN_DEACTIVATED_BIAS INT_MIN -/* SYSFS_TYPE_MASK and types are defined in include/linux/kernfs.h */ +/* KERNFS_TYPE_MASK and types are defined in include/linux/kernfs.h */ /** * kernfs_root - find out the kernfs_root a kernfs_node belongs to diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index f36e3f1b2477..a92284d3c73d 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -31,7 +31,7 @@ struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, int error; kn = sysfs_new_dirent(kernfs_root(parent), name, S_IFLNK|S_IRWXUGO, - SYSFS_KOBJ_LINK); + KERNFS_LINK); if (!kn) return ERR_PTR(-ENOMEM); diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 4a800017558d..aa007401bfc9 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -113,7 +113,7 @@ void sysfs_remove_dir(struct kobject *kobj) spin_unlock(&sysfs_symlink_target_lock); if (kn) { - WARN_ON_ONCE(sysfs_type(kn) != SYSFS_DIR); + WARN_ON_ONCE(kernfs_type(kn) != KERNFS_DIR); kernfs_remove(kn); } } diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index fd104b282f81..fe6388fbd154 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -29,7 +29,7 @@ static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn) { struct kobject *kobj = kn->parent->priv; - if (kn->flags & SYSFS_FLAG_LOCKDEP) + if (kn->flags & KERNFS_LOCKDEP) lockdep_assert_held(kn); return kobj->ktype ? kobj->ktype->sysfs_ops : NULL; } diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 0d48ea911508..aecb15f84557 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -183,7 +183,7 @@ int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, goto out; result = -EINVAL; - if (sysfs_type(kn) != SYSFS_KOBJ_LINK) + if (kernfs_type(kn) != KERNFS_LINK) goto out; if (kn->symlink.target_kn->priv != targ) goto out; diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 757647c4cb3b..e9c4e3a03960 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -28,22 +28,22 @@ struct kernfs_open_node; struct kernfs_iattrs; enum kernfs_node_type { - SYSFS_DIR = 0x0001, - SYSFS_KOBJ_ATTR = 0x0002, - SYSFS_KOBJ_LINK = 0x0004, + KERNFS_DIR = 0x0001, + KERNFS_FILE = 0x0002, + KERNFS_LINK = 0x0004, }; -#define SYSFS_TYPE_MASK 0x000f -#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) -#define SYSFS_ACTIVE_REF SYSFS_KOBJ_ATTR -#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK +#define KERNFS_TYPE_MASK 0x000f +#define KERNFS_COPY_NAME (KERNFS_DIR | KERNFS_LINK) +#define KERNFS_ACTIVE_REF KERNFS_FILE +#define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK enum kernfs_node_flag { - SYSFS_FLAG_REMOVED = 0x0010, - SYSFS_FLAG_NS = 0x0020, - SYSFS_FLAG_HAS_SEQ_SHOW = 0x0040, - SYSFS_FLAG_HAS_MMAP = 0x0080, - SYSFS_FLAG_LOCKDEP = 0x0100, + KERNFS_REMOVED = 0x0010, + KERNFS_NS = 0x0020, + KERNFS_HAS_SEQ_SHOW = 0x0040, + KERNFS_HAS_MMAP = 0x0080, + KERNFS_LOCKDEP = 0x0100, }; /* type-specific structures for kernfs_node union members */ @@ -170,9 +170,9 @@ struct kernfs_ops { #ifdef CONFIG_SYSFS -static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) +static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn) { - return kn->flags & SYSFS_TYPE_MASK; + return kn->flags & KERNFS_TYPE_MASK; } /** @@ -185,9 +185,9 @@ static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) */ static inline void kernfs_enable_ns(struct kernfs_node *kn) { - WARN_ON_ONCE(sysfs_type(kn) != SYSFS_DIR); + WARN_ON_ONCE(kernfs_type(kn) != KERNFS_DIR); WARN_ON_ONCE(!RB_EMPTY_ROOT(&kn->dir.children)); - kn->flags |= SYSFS_FLAG_NS; + kn->flags |= KERNFS_NS; } /** @@ -198,7 +198,7 @@ static inline void kernfs_enable_ns(struct kernfs_node *kn) */ static inline bool kernfs_ns_enabled(struct kernfs_node *kn) { - return kn->flags & SYSFS_FLAG_NS; + return kn->flags & KERNFS_NS; } struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, @@ -238,7 +238,7 @@ void kernfs_init(void); #else /* CONFIG_SYSFS */ -static inline enum kernfs_node_type sysfs_type(struct kernfs_node *kn) +static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn) { return 0; } /* whatever */ static inline void kernfs_enable_ns(struct kernfs_node *kn) { } -- cgit v1.2.3-59-g8ed1b From 61e7380403efbaf5f796e8cf979827c602bf6c50 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 7 Dec 2013 14:08:22 +0400 Subject: gpio: 74x164: Remove non-DT support Commit 20bc4d5d565159eb2b942bf4b7fae86fba94e32c (gpio: 74x164: Add support for the daisy-chaining) introduce check for DT for the driver, so driver cannot be used without DT. There are no in-tree users of this driver, so remove non-DT support completely. Signed-off-by: Alexander Shiyan Acked-by: Mark Brown Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 6 +++--- drivers/gpio/gpio-74x164.c | 14 +------------- include/linux/spi/74x164.h | 9 --------- 3 files changed, 4 insertions(+), 25 deletions(-) delete mode 100644 include/linux/spi/74x164.h (limited to 'include/linux') diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index ae3682d25a3c..4127f68412eb 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -714,10 +714,10 @@ config GPIO_MC33880 config GPIO_74X164 tristate "74x164 serial-in/parallel-out 8-bits shift register" - depends on SPI_MASTER + depends on SPI_MASTER && OF help - Platform driver for 74x164 compatible serial-in/parallel-out - 8-outputs shift registers. This driver can be used to provide access + Driver for 74x164 compatible serial-in/parallel-out 8-outputs + shift registers. This driver can be used to provide access to more gpio outputs. comment "AC97 GPIO expanders:" diff --git a/drivers/gpio/gpio-74x164.c b/drivers/gpio/gpio-74x164.c index ddb831232407..4d4e15ca67e0 100644 --- a/drivers/gpio/gpio-74x164.c +++ b/drivers/gpio/gpio-74x164.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -108,14 +107,8 @@ static int gen_74x164_direction_output(struct gpio_chip *gc, static int gen_74x164_probe(struct spi_device *spi) { struct gen_74x164_chip *chip; - struct gen_74x164_chip_platform_data *pdata; int ret; - if (!spi->dev.of_node) { - dev_err(&spi->dev, "No device tree data available.\n"); - return -EINVAL; - } - /* * bits_per_word cannot be configured in platform data */ @@ -129,12 +122,6 @@ static int gen_74x164_probe(struct spi_device *spi) if (!chip) return -ENOMEM; - pdata = dev_get_platdata(&spi->dev); - if (pdata && pdata->base) - chip->gpio_chip.base = pdata->base; - else - chip->gpio_chip.base = -1; - mutex_init(&chip->lock); spi_set_drvdata(spi, chip); @@ -145,6 +132,7 @@ static int gen_74x164_probe(struct spi_device *spi) chip->gpio_chip.direction_output = gen_74x164_direction_output; chip->gpio_chip.get = gen_74x164_get_value; chip->gpio_chip.set = gen_74x164_set_value; + chip->gpio_chip.base = -1; if (of_property_read_u32(spi->dev.of_node, "registers-number", &chip->registers)) { dev_err(&spi->dev, "Missing registers-number property in the DT.\n"); diff --git a/include/linux/spi/74x164.h b/include/linux/spi/74x164.h deleted file mode 100644 index 0aa6acc73317..000000000000 --- a/include/linux/spi/74x164.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef LINUX_SPI_74X164_H -#define LINUX_SPI_74X164_H - -struct gen_74x164_chip_platform_data { - /* number assigned to the first GPIO */ - unsigned base; -}; - -#endif -- cgit v1.2.3-59-g8ed1b From 2f6a1b6607fd6b0eb9501843a40e0c7555f37b4a Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Wed, 11 Dec 2013 13:27:11 -0500 Subject: macvlan: Remove custom recieve and forward handlers Since now macvlan and macvtap use the same receive and forward handlers, we can remove them completely and use netif_rx and dev_forward_skb() directly. Signed-off-by: Vlad Yasevich Signed-off-by: David S. Miller --- drivers/net/macvlan.c | 17 +++++------------ drivers/net/macvtap.c | 3 +-- include/linux/if_macvlan.h | 7 +------ 3 files changed, 7 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index cfb91570cddd..24ea994b6274 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -120,7 +120,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb, struct net_device *dev = vlan->dev; if (local) - return vlan->forward(dev, skb); + return dev_forward_skb(dev, skb); skb->dev = dev; if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) @@ -128,7 +128,7 @@ static int macvlan_broadcast_one(struct sk_buff *skb, else skb->pkt_type = PACKET_MULTICAST; - return vlan->receive(skb); + return netif_rx(skb); } static u32 macvlan_hash_mix(const struct macvlan_dev *vlan) @@ -251,7 +251,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb) skb->dev = dev; skb->pkt_type = PACKET_HOST; - ret = vlan->receive(skb); + ret = netif_rx(skb); out: macvlan_count_rx(vlan, len, ret == NET_RX_SUCCESS, 0); @@ -803,10 +803,7 @@ static int macvlan_validate(struct nlattr *tb[], struct nlattr *data[]) } int macvlan_common_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[], - int (*receive)(struct sk_buff *skb), - int (*forward)(struct net_device *dev, - struct sk_buff *skb)) + struct nlattr *tb[], struct nlattr *data[]) { struct macvlan_dev *vlan = netdev_priv(dev); struct macvlan_port *port; @@ -848,8 +845,6 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, vlan->lowerdev = lowerdev; vlan->dev = dev; vlan->port = port; - vlan->receive = receive; - vlan->forward = forward; vlan->set_features = MACVLAN_FEATURES; vlan->mode = MACVLAN_MODE_VEPA; @@ -894,9 +889,7 @@ EXPORT_SYMBOL_GPL(macvlan_common_newlink); static int macvlan_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { - return macvlan_common_newlink(src_net, dev, tb, data, - netif_rx, - dev_forward_skb); + return macvlan_common_newlink(src_net, dev, tb, data); } void macvlan_dellink(struct net_device *dev, struct list_head *head) diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 85ecfccf9c60..64409af0da31 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -400,8 +400,7 @@ static int macvtap_newlink(struct net *src_net, /* Don't put anything that may fail after macvlan_common_newlink * because we can't undo what it does. */ - return macvlan_common_newlink(src_net, dev, tb, data, - netif_rx, dev_forward_skb); + return macvlan_common_newlink(src_net, dev, tb, data); } static void macvtap_dellink(struct net_device *dev, diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h index 84ba5ac39e03..ea22721ba269 100644 --- a/include/linux/if_macvlan.h +++ b/include/linux/if_macvlan.h @@ -69,8 +69,6 @@ struct macvlan_dev { netdev_features_t set_features; enum macvlan_mode mode; u16 flags; - int (*receive)(struct sk_buff *skb); - int (*forward)(struct net_device *dev, struct sk_buff *skb); /* This array tracks active taps. */ struct macvtap_queue __rcu *taps[MAX_MACVTAP_QUEUES]; /* This list tracks all taps (both enabled and disabled) */ @@ -103,10 +101,7 @@ static inline void macvlan_count_rx(const struct macvlan_dev *vlan, extern void macvlan_common_setup(struct net_device *dev); extern int macvlan_common_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[], - int (*receive)(struct sk_buff *skb), - int (*forward)(struct net_device *dev, - struct sk_buff *skb)); + struct nlattr *tb[], struct nlattr *data[]); extern void macvlan_count_rx(const struct macvlan_dev *vlan, unsigned int len, bool success, -- cgit v1.2.3-59-g8ed1b From 299603e8370a93dd5d8e8d800f0dff1ce2c53d36 Mon Sep 17 00:00:00 2001 From: Jerry Chu Date: Wed, 11 Dec 2013 20:53:45 -0800 Subject: net-gro: Prepare GRO stack for the upcoming tunneling support This patch modifies the GRO stack to avoid the use of "network_header" and associated macros like ip_hdr() and ipv6_hdr() in order to allow an arbitary number of IP hdrs (v4 or v6) to be used in the encapsulation chain. This lays the foundation for various IP tunneling support (IP-in-IP, GRE, VXLAN, SIT,...) to be added later. With this patch, the GRO stack traversing now is mostly based on skb_gro_offset rather than special hdr offsets saved in skb (e.g., skb->network_header). As a result all but the top layer (i.e., the the transport layer) must have hdrs of the same length in order for a pkt to be considered for aggregation. Therefore when adding a new encap layer (e.g., for tunneling), one must check and skip flows (e.g., by setting NAPI_GRO_CB(p)->same_flow to 0) that have a different hdr length. Note that unlike the network header, the transport header can and will continue to be set by the GRO code since there will be at most one "transport layer" in the encap chain. Signed-off-by: H.K. Jerry Chu Suggested-by: Eric Dumazet Reviewed-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/netdevice.h | 2 +- net/core/dev.c | 76 ++++++++++++++++------------------------------- net/ipv4/af_inet.c | 25 ++++++++++++---- net/ipv4/tcp_offload.c | 9 +++--- net/ipv6/ip6_offload.c | 54 ++++++++++++++++++++++++++------- net/ipv6/tcpv6_offload.c | 6 ++-- 6 files changed, 97 insertions(+), 75 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 0ca8100f9fbc..5260d2eae2e6 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1676,7 +1676,7 @@ struct offload_callbacks { int (*gso_send_check)(struct sk_buff *skb); struct sk_buff **(*gro_receive)(struct sk_buff **head, struct sk_buff *skb); - int (*gro_complete)(struct sk_buff *skb); + int (*gro_complete)(struct sk_buff *skb, int nhoff); }; struct packet_offload { diff --git a/net/core/dev.c b/net/core/dev.c index 355df36360b4..c95d664b2b42 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3752,7 +3752,7 @@ static int napi_gro_complete(struct sk_buff *skb) if (ptype->type != type || !ptype->callbacks.gro_complete) continue; - err = ptype->callbacks.gro_complete(skb); + err = ptype->callbacks.gro_complete(skb, 0); break; } rcu_read_unlock(); @@ -3818,6 +3818,23 @@ static void gro_list_prepare(struct napi_struct *napi, struct sk_buff *skb) } } +static void skb_gro_reset_offset(struct sk_buff *skb) +{ + const struct skb_shared_info *pinfo = skb_shinfo(skb); + const skb_frag_t *frag0 = &pinfo->frags[0]; + + NAPI_GRO_CB(skb)->data_offset = 0; + NAPI_GRO_CB(skb)->frag0 = NULL; + NAPI_GRO_CB(skb)->frag0_len = 0; + + if (skb_mac_header(skb) == skb_tail_pointer(skb) && + pinfo->nr_frags && + !PageHighMem(skb_frag_page(frag0))) { + NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0); + NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(frag0); + } +} + static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { struct sk_buff **pp = NULL; @@ -3833,6 +3850,7 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff if (skb_is_gso(skb) || skb_has_frag_list(skb)) goto normal; + skb_gro_reset_offset(skb); gro_list_prepare(napi, skb); rcu_read_lock(); @@ -3938,27 +3956,8 @@ static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) return ret; } -static void skb_gro_reset_offset(struct sk_buff *skb) -{ - const struct skb_shared_info *pinfo = skb_shinfo(skb); - const skb_frag_t *frag0 = &pinfo->frags[0]; - - NAPI_GRO_CB(skb)->data_offset = 0; - NAPI_GRO_CB(skb)->frag0 = NULL; - NAPI_GRO_CB(skb)->frag0_len = 0; - - if (skb_mac_header(skb) == skb_tail_pointer(skb) && - pinfo->nr_frags && - !PageHighMem(skb_frag_page(frag0))) { - NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0); - NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(frag0); - } -} - gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) { - skb_gro_reset_offset(skb); - return napi_skb_finish(dev_gro_receive(napi, skb), skb); } EXPORT_SYMBOL(napi_gro_receive); @@ -3992,12 +3991,7 @@ static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff * { switch (ret) { case GRO_NORMAL: - case GRO_HELD: - skb->protocol = eth_type_trans(skb, skb->dev); - - if (ret == GRO_HELD) - skb_gro_pull(skb, -ETH_HLEN); - else if (netif_receive_skb(skb)) + if (netif_receive_skb(skb)) ret = GRO_DROP; break; @@ -4006,6 +4000,7 @@ static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff * napi_reuse_skb(napi, skb); break; + case GRO_HELD: case GRO_MERGED: break; } @@ -4016,36 +4011,15 @@ static gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff * static struct sk_buff *napi_frags_skb(struct napi_struct *napi) { struct sk_buff *skb = napi->skb; - struct ethhdr *eth; - unsigned int hlen; - unsigned int off; napi->skb = NULL; - skb_reset_mac_header(skb); - skb_gro_reset_offset(skb); - - off = skb_gro_offset(skb); - hlen = off + sizeof(*eth); - eth = skb_gro_header_fast(skb, off); - if (skb_gro_header_hard(skb, hlen)) { - eth = skb_gro_header_slow(skb, hlen, off); - if (unlikely(!eth)) { - napi_reuse_skb(napi, skb); - skb = NULL; - goto out; - } + if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr)))) { + napi_reuse_skb(napi, skb); + return NULL; } + skb->protocol = eth_type_trans(skb, skb->dev); - skb_gro_pull(skb, sizeof(*eth)); - - /* - * This works because the only protocols we care about don't require - * special handling. We'll fix it up properly at the end. - */ - skb->protocol = eth->h_proto; - -out: return skb; } diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 70011e029ac1..ef4f9df6d698 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1377,8 +1377,12 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, if (!NAPI_GRO_CB(p)->same_flow) continue; - iph2 = ip_hdr(p); - + iph2 = (struct iphdr *)(p->data + off); + /* The above works because, with the exception of the top + * (inner most) layer, we only aggregate pkts with the same + * hdr length so all the hdrs we'll need to verify will start + * at the same offset. + */ if ((iph->protocol ^ iph2->protocol) | ((__force u32)iph->saddr ^ (__force u32)iph2->saddr) | ((__force u32)iph->daddr ^ (__force u32)iph2->daddr)) { @@ -1397,6 +1401,11 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head, } NAPI_GRO_CB(skb)->flush |= flush; + skb_set_network_header(skb, off); + /* The above will be needed by the transport layer if there is one + * immediately following this IP hdr. + */ + skb_gro_pull(skb, sizeof(*iph)); skb_set_transport_header(skb, skb_gro_offset(skb)); @@ -1411,10 +1420,10 @@ out: return pp; } -static int inet_gro_complete(struct sk_buff *skb) +static int inet_gro_complete(struct sk_buff *skb, int nhoff) { - __be16 newlen = htons(skb->len - skb_network_offset(skb)); - struct iphdr *iph = ip_hdr(skb); + __be16 newlen = htons(skb->len - nhoff); + struct iphdr *iph = (struct iphdr *)(skb->data + nhoff); const struct net_offload *ops; int proto = iph->protocol; int err = -ENOSYS; @@ -1427,7 +1436,11 @@ static int inet_gro_complete(struct sk_buff *skb) if (WARN_ON(!ops || !ops->callbacks.gro_complete)) goto out_unlock; - err = ops->callbacks.gro_complete(skb); + /* Only need to add sizeof(*iph) to get to the next hdr below + * because any hdr with option will have been flushed in + * inet_gro_receive(). + */ + err = ops->callbacks.gro_complete(skb, nhoff + sizeof(*iph)); out_unlock: rcu_read_unlock(); diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index 05606353c7e7..2658a27f540d 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c @@ -240,7 +240,7 @@ int tcp_gro_complete(struct sk_buff *skb) { struct tcphdr *th = tcp_hdr(skb); - skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_start = (unsigned char *)th - skb->head; skb->csum_offset = offsetof(struct tcphdr, check); skb->ip_summed = CHECKSUM_PARTIAL; @@ -272,6 +272,7 @@ static int tcp_v4_gso_send_check(struct sk_buff *skb) static struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb) { + /* Use the IP hdr immediately proceeding for this transport */ const struct iphdr *iph = skb_gro_network_header(skb); __wsum wsum; @@ -303,13 +304,13 @@ skip_csum: return tcp_gro_receive(head, skb); } -static int tcp4_gro_complete(struct sk_buff *skb) +static int tcp4_gro_complete(struct sk_buff *skb, int thoff) { const struct iphdr *iph = ip_hdr(skb); struct tcphdr *th = tcp_hdr(skb); - th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb), - iph->saddr, iph->daddr, 0); + th->check = ~tcp_v4_check(skb->len - thoff, iph->saddr, + iph->daddr, 0); skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; return tcp_gro_complete(skb); diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index 4b851692b1f6..7540a0ed75ae 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c @@ -154,6 +154,35 @@ out: return segs; } +/* Return the total length of all the extension hdrs, following the same + * logic in ipv6_gso_pull_exthdrs() when parsing ext-hdrs. + */ +static int ipv6_exthdrs_len(struct ipv6hdr *iph, + const struct net_offload **opps) +{ + struct ipv6_opt_hdr *opth = NULL; + int len = 0, proto, optlen; + + proto = iph->nexthdr; + for (;;) { + if (proto != NEXTHDR_HOP) { + *opps = rcu_dereference(inet6_offloads[proto]); + if (unlikely(!(*opps))) + break; + if (!((*opps)->flags & INET6_PROTO_GSO_EXTHDR)) + break; + } + if (opth == NULL) + opth = (void *)(iph+1); + else + opth = (void *)opth + optlen; + optlen = ipv6_optlen(opth); + len += optlen; + proto = opth->nexthdr; + } + return len; +} + static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, struct sk_buff *skb) { @@ -177,6 +206,7 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, goto out; } + skb_set_network_header(skb, off); skb_gro_pull(skb, sizeof(*iph)); skb_set_transport_header(skb, skb_gro_offset(skb)); @@ -211,12 +241,16 @@ static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, if (!NAPI_GRO_CB(p)->same_flow) continue; - iph2 = ipv6_hdr(p); + iph2 = (struct ipv6hdr *)(p->data + off); first_word = *(__be32 *)iph ^ *(__be32 *)iph2 ; - /* All fields must match except length and Traffic Class. */ - if (nlen != skb_network_header_len(p) || - (first_word & htonl(0xF00FFFFF)) || + /* All fields must match except length and Traffic Class. + * XXX skbs on the gro_list have all been parsed and pulled + * already so we don't need to compare nlen + * (nlen != (sizeof(*iph2) + ipv6_exthdrs_len(iph2, &ops))) + * memcmp() alone below is suffcient, right? + */ + if ((first_word & htonl(0xF00FFFFF)) || memcmp(&iph->nexthdr, &iph2->nexthdr, nlen - offsetof(struct ipv6hdr, nexthdr))) { NAPI_GRO_CB(p)->same_flow = 0; @@ -245,21 +279,21 @@ out: return pp; } -static int ipv6_gro_complete(struct sk_buff *skb) +static int ipv6_gro_complete(struct sk_buff *skb, int nhoff) { const struct net_offload *ops; - struct ipv6hdr *iph = ipv6_hdr(skb); + struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + nhoff); int err = -ENOSYS; - iph->payload_len = htons(skb->len - skb_network_offset(skb) - - sizeof(*iph)); + iph->payload_len = htons(skb->len - nhoff - sizeof(*iph)); rcu_read_lock(); - ops = rcu_dereference(inet6_offloads[NAPI_GRO_CB(skb)->proto]); + + nhoff += sizeof(*iph) + ipv6_exthdrs_len(iph, &ops); if (WARN_ON(!ops || !ops->callbacks.gro_complete)) goto out_unlock; - err = ops->callbacks.gro_complete(skb); + err = ops->callbacks.gro_complete(skb, nhoff); out_unlock: rcu_read_unlock(); diff --git a/net/ipv6/tcpv6_offload.c b/net/ipv6/tcpv6_offload.c index 6d18157dc32c..0d78132ff18a 100644 --- a/net/ipv6/tcpv6_offload.c +++ b/net/ipv6/tcpv6_offload.c @@ -66,13 +66,13 @@ skip_csum: return tcp_gro_receive(head, skb); } -static int tcp6_gro_complete(struct sk_buff *skb) +static int tcp6_gro_complete(struct sk_buff *skb, int thoff) { const struct ipv6hdr *iph = ipv6_hdr(skb); struct tcphdr *th = tcp_hdr(skb); - th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb), - &iph->saddr, &iph->daddr, 0); + th->check = ~tcp_v6_check(skb->len - thoff, &iph->saddr, + &iph->daddr, 0); skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; return tcp_gro_complete(skb); -- cgit v1.2.3-59-g8ed1b From 1933861db4f7c9beecca5cc7460c6c814554cc34 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 3 Dec 2013 15:15:21 +0100 Subject: usb: gadget: configfs: allow setting function instance's name USB function's configfs config group is created in a generic way in usb/gadget/configfs.c:function_make(), which in turn delegates actual allocation and setup of the USB function instance to a particular implementation, e.g. in f_acm.c. The said implementation does its job in a parameter-less function e.g. acm_alloc_instance(), which results in creating an unnamed config group, whose name is set later in function_make(). function_make() creates the name by parsing a string of the form: . which comes from userspace as a parameter to mkdir invocation. Up to now only has been used, while has been ignored. This patch adds a set_inst_name() operation to struct usb_function_instance which allows passing the from function_make() so that it is not ignored. It is entirely up to the implementor of set_inst_name() what to do with the . In a typical case, the struct usb_function_instance is embedded in a larger struct which is retrieved in set_inst_name() with container_of(), and the larger struct contains a field to store the . Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/configfs.c | 7 +++++++ include/linux/usb/composite.h | 2 ++ 2 files changed, 9 insertions(+) (limited to 'include/linux') diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 25885112fa35..d6c8ab4a5327 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -564,6 +564,13 @@ static struct config_group *function_make( usb_put_function_instance(fi); return ERR_PTR(ret); } + if (fi->set_inst_name) { + ret = fi->set_inst_name(fi, instance_name); + if (ret) { + usb_put_function_instance(fi); + return ERR_PTR(ret); + } + } gi = container_of(group, struct gadget_info, functions_group); diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 5e61589fc166..dba63f53906c 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -468,6 +468,8 @@ struct usb_function_instance { struct config_group group; struct list_head cfs_list; struct usb_function_driver *fd; + int (*set_inst_name)(struct usb_function_instance *inst, + const char *name); void (*free_func_inst)(struct usb_function_instance *inst); }; -- cgit v1.2.3-59-g8ed1b From 4b187fceec3c731815ff8e6a7317fd5ba50d1d5d Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 3 Dec 2013 15:15:32 +0100 Subject: usb: gadget: FunctionFS: add devices management code This will be required in order to use the new function interface (usb_get_function_instance/usb_put_function_instance) Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyunmgin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_fs.c | 238 +++++++++++++++++++++++++++++++++++++++-- drivers/usb/gadget/g_ffs.c | 175 ++++++++++-------------------- drivers/usb/gadget/u_fs.h | 24 +++++ include/linux/usb/functionfs.h | 14 --- 4 files changed, 314 insertions(+), 137 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index c0b4cf808638..d17930d9a843 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -90,7 +90,7 @@ enum ffs_state { /* * We've got descriptors and strings. We are or have called - * functionfs_ready_callback(). functionfs_bind() may have + * ffs_ready(). functionfs_bind() may have * been called but we don't know. * * This is the only state in which operations on epfiles may @@ -103,7 +103,7 @@ enum ffs_state { * we encounter an unrecoverable error. The only * unrecoverable error is situation when after reading strings * from user space we fail to initialise epfiles or - * functionfs_ready_callback() returns with error (<0). + * ffs_ready() returns with error (<0). * * In this state no open(2), read(2) or write(2) (both on ep0 * as well as epfile) may succeed (at this point epfiles are @@ -361,6 +361,15 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data, const struct file_operations *fops, struct dentry **dentry_p); +/* Devices management *******************************************************/ + +DEFINE_MUTEX(ffs_lock); + +static struct ffs_dev *ffs_find_dev(const char *name); +static void *ffs_acquire_dev(const char *dev_name); +static void ffs_release_dev(struct ffs_data *ffs_data); +static int ffs_ready(struct ffs_data *ffs); +static void ffs_closed(struct ffs_data *ffs); /* Misc helper functions ****************************************************/ @@ -486,7 +495,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, ffs->state = FFS_ACTIVE; mutex_unlock(&ffs->mutex); - ret = functionfs_ready_callback(ffs); + ret = ffs_ready(ffs); if (unlikely(ret < 0)) { ffs->state = FFS_CLOSING; return ret; @@ -1218,7 +1227,7 @@ ffs_fs_mount(struct file_system_type *t, int flags, return ERR_PTR(-ENOMEM); } - ffs_dev = functionfs_acquire_dev_callback(dev_name); + ffs_dev = ffs_acquire_dev(dev_name); if (IS_ERR(ffs_dev)) { ffs_data_put(ffs); return ERR_CAST(ffs_dev); @@ -1228,7 +1237,7 @@ ffs_fs_mount(struct file_system_type *t, int flags, rv = mount_nodev(t, flags, &data, ffs_sb_fill); if (IS_ERR(rv) && data.ffs_data) { - functionfs_release_dev_callback(data.ffs_data); + ffs_release_dev(data.ffs_data); ffs_data_put(data.ffs_data); } return rv; @@ -1241,7 +1250,7 @@ ffs_fs_kill_sb(struct super_block *sb) kill_litter_super(sb); if (sb->s_fs_info) { - functionfs_release_dev_callback(sb->s_fs_info); + ffs_release_dev(sb->s_fs_info); ffs_data_put(sb->s_fs_info); } } @@ -1354,7 +1363,7 @@ static void ffs_data_clear(struct ffs_data *ffs) ENTER(); if (test_and_clear_bit(FFS_FL_CALL_CLOSED_CALLBACK, &ffs->flags)) - functionfs_closed_callback(ffs); + ffs_closed(ffs); BUG_ON(ffs->gadget); @@ -2466,6 +2475,221 @@ static int ffs_func_revmap_intf(struct ffs_function *func, u8 intf) } +/* Devices management *******************************************************/ + +static LIST_HEAD(ffs_devices); + +static struct ffs_dev *_ffs_find_dev(const char *name) +{ + struct ffs_dev *dev; + + list_for_each_entry(dev, &ffs_devices, entry) { + if (!dev->name || !name) + continue; + if (strcmp(dev->name, name) == 0) + return dev; + } + + return NULL; +} + +/* + * ffs_lock must be taken by the caller of this function + */ +static struct ffs_dev *ffs_get_single_dev(void) +{ + struct ffs_dev *dev; + + if (list_is_singular(&ffs_devices)) { + dev = list_first_entry(&ffs_devices, struct ffs_dev, entry); + if (dev->single) + return dev; + } + + return NULL; +} + +/* + * ffs_lock must be taken by the caller of this function + */ +static struct ffs_dev *ffs_find_dev(const char *name) +{ + struct ffs_dev *dev; + + dev = ffs_get_single_dev(); + if (dev) + return dev; + + return _ffs_find_dev(name); +} + +/* + * ffs_lock must be taken by the caller of this function + */ +struct ffs_dev *ffs_alloc_dev(void) +{ + struct ffs_dev *dev; + int ret; + + if (ffs_get_single_dev()) + return ERR_PTR(-EBUSY); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (list_empty(&ffs_devices)) { + ret = functionfs_init(); + if (ret) { + kfree(dev); + return ERR_PTR(ret); + } + } + + list_add(&dev->entry, &ffs_devices); + + return dev; +} + +/* + * ffs_lock must be taken by the caller of this function + * The caller is responsible for "name" being available whenever f_fs needs it + */ +static int _ffs_name_dev(struct ffs_dev *dev, const char *name) +{ + struct ffs_dev *existing; + + existing = _ffs_find_dev(name); + if (existing) + return -EBUSY; + + dev->name = name; + + return 0; +} + +/* + * The caller is responsible for "name" being available whenever f_fs needs it + */ +int ffs_name_dev(struct ffs_dev *dev, const char *name) +{ + int ret; + + ffs_dev_lock(); + ret = _ffs_name_dev(dev, name); + ffs_dev_unlock(); + + return ret; +} + +int ffs_single_dev(struct ffs_dev *dev) +{ + int ret; + + ret = 0; + ffs_dev_lock(); + + if (!list_is_singular(&ffs_devices)) + ret = -EBUSY; + else + dev->single = true; + + ffs_dev_unlock(); + return ret; +} + +/* + * ffs_lock must be taken by the caller of this function + */ +void ffs_free_dev(struct ffs_dev *dev) +{ + list_del(&dev->entry); + kfree(dev); + if (list_empty(&ffs_devices)) + functionfs_cleanup(); +} + +static void *ffs_acquire_dev(const char *dev_name) +{ + struct ffs_dev *ffs_dev; + + ENTER(); + ffs_dev_lock(); + + ffs_dev = ffs_find_dev(dev_name); + if (!ffs_dev) + ffs_dev = ERR_PTR(-ENODEV); + else if (ffs_dev->mounted) + ffs_dev = ERR_PTR(-EBUSY); + else + ffs_dev->mounted = true; + + ffs_dev_unlock(); + return ffs_dev; +} + +static void ffs_release_dev(struct ffs_data *ffs_data) +{ + struct ffs_dev *ffs_dev; + + ENTER(); + ffs_dev_lock(); + + ffs_dev = ffs_data->private_data; + if (ffs_dev) + ffs_dev->mounted = false; + + ffs_dev_unlock(); +} + +static int ffs_ready(struct ffs_data *ffs) +{ + struct ffs_dev *ffs_obj; + int ret = 0; + + ENTER(); + ffs_dev_lock(); + + ffs_obj = ffs->private_data; + if (!ffs_obj) { + ret = -EINVAL; + goto done; + } + if (WARN_ON(ffs_obj->desc_ready)) { + ret = -EBUSY; + goto done; + } + + ffs_obj->desc_ready = true; + ffs_obj->ffs_data = ffs; + + if (ffs_obj->ffs_ready_callback) + ret = ffs_obj->ffs_ready_callback(ffs); + +done: + ffs_dev_unlock(); + return ret; +} + +static void ffs_closed(struct ffs_data *ffs) +{ + struct ffs_dev *ffs_obj; + + ENTER(); + ffs_dev_lock(); + + ffs_obj = ffs->private_data; + if (!ffs_obj) + goto done; + + ffs_obj->desc_ready = false; + + if (ffs_obj->ffs_closed_callback) + ffs_obj->ffs_closed_callback(ffs); +done: + ffs_dev_unlock(); +} + /* Misc helper functions ****************************************************/ static int ffs_mutex_lock(struct mutex *mutex, unsigned nonblock) diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index 1aaa103e01c6..074df0d56255 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -157,6 +157,8 @@ struct gfs_configuration { #endif }; +static int functionfs_ready_callback(struct ffs_data *ffs); +static void functionfs_closed_callback(struct ffs_data *ffs); static int gfs_bind(struct usb_composite_dev *cdev); static int gfs_unbind(struct usb_composite_dev *cdev); static int gfs_do_config(struct usb_configuration *c); @@ -170,172 +172,113 @@ static __refdata struct usb_composite_driver gfs_driver = { .unbind = gfs_unbind, }; -static DEFINE_MUTEX(gfs_lock); static unsigned int missing_funcs; static bool gfs_registered; static bool gfs_single_func; -static struct ffs_dev *ffs_tab; +static struct ffs_dev **ffs_tab; static int __init gfs_init(void) { int i; + int ret = 0; ENTER(); - if (!func_num) { + if (func_num < 2) { gfs_single_func = true; func_num = 1; } - ffs_tab = kcalloc(func_num, sizeof *ffs_tab, GFP_KERNEL); + ffs_tab = kcalloc(func_num, sizeof(*ffs_tab), GFP_KERNEL); if (!ffs_tab) return -ENOMEM; - if (!gfs_single_func) - for (i = 0; i < func_num; i++) - ffs_tab[i].name = func_names[i]; + for (i = 0; i < func_num; i++) { + ffs_dev_lock(); + ffs_tab[i] = ffs_alloc_dev(); + ffs_dev_unlock(); + if (IS_ERR(ffs_tab[i])) { + ret = PTR_ERR(ffs_tab[i]); + --i; + goto no_dev; + } + if (gfs_single_func) + ret = ffs_single_dev(ffs_tab[i]); + else + ret = ffs_name_dev(ffs_tab[i], func_names[i]); + if (ret) + goto no_dev; + ffs_tab[i]->ffs_ready_callback = functionfs_ready_callback; + ffs_tab[i]->ffs_closed_callback = functionfs_closed_callback; + } missing_funcs = func_num; - return functionfs_init(); + return 0; +no_dev: + ffs_dev_lock(); + while (i >= 0) + ffs_free_dev(ffs_tab[i--]); + ffs_dev_unlock(); + kfree(ffs_tab); + return ret; } module_init(gfs_init); static void __exit gfs_exit(void) { + int i; + ENTER(); - mutex_lock(&gfs_lock); + ffs_dev_lock(); if (gfs_registered) usb_composite_unregister(&gfs_driver); gfs_registered = false; - functionfs_cleanup(); - - mutex_unlock(&gfs_lock); + for (i = 0; i < func_num; i++) + ffs_free_dev(ffs_tab[i]); + ffs_dev_unlock(); kfree(ffs_tab); } module_exit(gfs_exit); -static struct ffs_dev *gfs_find_dev(const char *dev_name) -{ - int i; - - ENTER(); - - if (gfs_single_func) - return &ffs_tab[0]; - - for (i = 0; i < func_num; i++) - if (strcmp(ffs_tab[i].name, dev_name) == 0) - return &ffs_tab[i]; - - return NULL; -} - +/* + * The caller of this function takes ffs_lock + */ static int functionfs_ready_callback(struct ffs_data *ffs) { - struct ffs_dev *ffs_obj; - int ret; - - ENTER(); - mutex_lock(&gfs_lock); + int ret = 0; - ffs_obj = ffs->private_data; - if (!ffs_obj) { - ret = -EINVAL; - goto done; - } - - if (WARN_ON(ffs_obj->desc_ready)) { - ret = -EBUSY; - goto done; - } - ffs_obj->desc_ready = true; - ffs_obj->ffs_data = ffs; + if (--missing_funcs) + return 0; - if (--missing_funcs) { - ret = 0; - goto done; - } + if (gfs_registered) + return -EBUSY; - if (gfs_registered) { - ret = -EBUSY; - goto done; - } gfs_registered = true; ret = usb_composite_probe(&gfs_driver); if (unlikely(ret < 0)) gfs_registered = false; - -done: - mutex_unlock(&gfs_lock); + return ret; } +/* + * The caller of this function takes ffs_lock + */ static void functionfs_closed_callback(struct ffs_data *ffs) { - struct ffs_dev *ffs_obj; - - ENTER(); - mutex_lock(&gfs_lock); - - ffs_obj = ffs->private_data; - if (!ffs_obj) - goto done; - - ffs_obj->desc_ready = false; missing_funcs++; if (gfs_registered) usb_composite_unregister(&gfs_driver); gfs_registered = false; - -done: - mutex_unlock(&gfs_lock); -} - -static void *functionfs_acquire_dev_callback(const char *dev_name) -{ - struct ffs_dev *ffs_dev; - - ENTER(); - mutex_lock(&gfs_lock); - - ffs_dev = gfs_find_dev(dev_name); - if (!ffs_dev) { - ffs_dev = ERR_PTR(-ENODEV); - goto done; - } - - if (ffs_dev->mounted) { - ffs_dev = ERR_PTR(-EBUSY); - goto done; - } - ffs_dev->mounted = true; - -done: - mutex_unlock(&gfs_lock); - return ffs_dev; -} - -static void functionfs_release_dev_callback(struct ffs_data *ffs_data) -{ - struct ffs_dev *ffs_dev; - - ENTER(); - mutex_lock(&gfs_lock); - - ffs_dev = ffs_data->private_data; - if (ffs_dev) - ffs_dev->mounted = false; - - mutex_unlock(&gfs_lock); } /* - * It is assumed that gfs_bind is called from a context where gfs_lock is held + * It is assumed that gfs_bind is called from a context where ffs_lock is held */ static int gfs_bind(struct usb_composite_dev *cdev) { @@ -422,10 +365,10 @@ static int gfs_bind(struct usb_composite_dev *cdev) gfs_dev_desc.iProduct = gfs_strings[USB_GADGET_PRODUCT_IDX].id; for (i = func_num; i--; ) { - ret = functionfs_bind(ffs_tab[i].ffs_data, cdev); + ret = functionfs_bind(ffs_tab[i]->ffs_data, cdev); if (unlikely(ret < 0)) { while (++i < func_num) - functionfs_unbind(ffs_tab[i].ffs_data); + functionfs_unbind(ffs_tab[i]->ffs_data); goto error_rndis; } } @@ -448,7 +391,7 @@ static int gfs_bind(struct usb_composite_dev *cdev) error_unbind: for (i = 0; i < func_num; i++) - functionfs_unbind(ffs_tab[i].ffs_data); + functionfs_unbind(ffs_tab[i]->ffs_data); error_rndis: #ifdef CONFIG_USB_FUNCTIONFS_RNDIS usb_put_function_instance(fi_rndis); @@ -464,7 +407,7 @@ error: } /* - * It is assumed that gfs_unbind is called from a context where gfs_lock is held + * It is assumed that gfs_unbind is called from a context where ffs_lock is held */ static int gfs_unbind(struct usb_composite_dev *cdev) { @@ -497,15 +440,15 @@ static int gfs_unbind(struct usb_composite_dev *cdev) * do...? */ for (i = func_num; i--; ) - if (ffs_tab[i].ffs_data) - functionfs_unbind(ffs_tab[i].ffs_data); + if (ffs_tab[i]->ffs_data) + functionfs_unbind(ffs_tab[i]->ffs_data); return 0; } /* * It is assumed that gfs_do_config is called from a context where - * gfs_lock is held + * ffs_lock is held */ static int gfs_do_config(struct usb_configuration *c) { @@ -529,7 +472,7 @@ static int gfs_do_config(struct usb_configuration *c) } for (i = 0; i < func_num; i++) { - ret = functionfs_bind_config(c->cdev, c, ffs_tab[i].ffs_data); + ret = functionfs_bind_config(c->cdev, c, ffs_tab[i]->ffs_data); if (unlikely(ret < 0)) return ret; } diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h index 5d9229a01560..2d00f9d296a3 100644 --- a/drivers/usb/gadget/u_fs.h +++ b/drivers/usb/gadget/u_fs.h @@ -17,12 +17,36 @@ #define U_FFS_H #include +#include +#include struct ffs_dev { const char *name; bool mounted; bool desc_ready; + bool single; struct ffs_data *ffs_data; + struct list_head entry; + + int (*ffs_ready_callback)(struct ffs_data *ffs); + void (*ffs_closed_callback)(struct ffs_data *ffs); }; +extern struct mutex ffs_lock; + +static inline void ffs_dev_lock(void) +{ + mutex_lock(&ffs_lock); +} + +static inline void ffs_dev_unlock(void) +{ + mutex_unlock(&ffs_lock); +} + +struct ffs_dev *ffs_alloc_dev(void); +int ffs_name_dev(struct ffs_dev *dev, const char *name); +int ffs_single_dev(struct ffs_dev *dev); +void ffs_free_dev(struct ffs_dev *dev); + #endif /* U_FFS_H */ diff --git a/include/linux/usb/functionfs.h b/include/linux/usb/functionfs.h index 65d0a88dbc67..9c1e92620dfb 100644 --- a/include/linux/usb/functionfs.h +++ b/include/linux/usb/functionfs.h @@ -8,10 +8,6 @@ struct ffs_data; struct usb_composite_dev; struct usb_configuration; - -static int functionfs_init(void) __attribute__((warn_unused_result)); -static void functionfs_cleanup(void); - static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) __attribute__((warn_unused_result, nonnull)); static void functionfs_unbind(struct ffs_data *ffs) @@ -23,14 +19,4 @@ static int functionfs_bind_config(struct usb_composite_dev *cdev, __attribute__((warn_unused_result, nonnull)); -static int functionfs_ready_callback(struct ffs_data *ffs) - __attribute__((warn_unused_result, nonnull)); -static void functionfs_closed_callback(struct ffs_data *ffs) - __attribute__((nonnull)); -static void *functionfs_acquire_dev_callback(const char *dev_name) - __attribute__((warn_unused_result, nonnull)); -static void functionfs_release_dev_callback(struct ffs_data *ffs_data) - __attribute__((nonnull)); - - #endif -- cgit v1.2.3-59-g8ed1b From 5920cda627688c3229fd63157ff031f3f174175e Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 3 Dec 2013 15:15:33 +0100 Subject: usb: gadget: FunctionFS: convert to new function interface with backward compatibility This is required in order to integrate configfs support. f_fs needs to be a separately compiled module and so it needs to use the new interface. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/gadget/Kconfig | 3 + drivers/usb/gadget/Makefile | 2 + drivers/usb/gadget/f_fs.c | 422 +++++++++++++++++++++-------------------- drivers/usb/gadget/g_ffs.c | 1 + drivers/usb/gadget/u_fs.h | 214 +++++++++++++++++++++ include/linux/usb/functionfs.h | 2 + 6 files changed, 435 insertions(+), 209 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index aa3610ea9d9f..1761a3b8b31a 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -539,6 +539,9 @@ config USB_F_RNDIS config USB_F_MASS_STORAGE tristate +config USB_F_FS + tristate + choice tristate "USB Gadget Drivers" default USB_ETH diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 0c40277931f4..6cccdfed140c 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -61,6 +61,8 @@ usb_f_rndis-y := f_rndis.o rndis.o obj-$(CONFIG_USB_F_RNDIS) += usb_f_rndis.o usb_f_mass_storage-y := f_mass_storage.o storage_common.o obj-$(CONFIG_USB_F_MASS_STORAGE)+= usb_f_mass_storage.o +usb_f_fs-y := f_fs.o +obj-$(CONFIG_USB_F_FS) += usb_f_fs.o # # USB gadget drivers diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index d17930d9a843..8d318eaaaf20 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -57,210 +58,6 @@ #define vla_ptr(ptr, groupname, name) \ ((void *) ((char *)ptr + groupname##_##name##__offset)) -/* Debugging ****************************************************************/ - -#ifdef VERBOSE_DEBUG -#ifndef pr_vdebug -# define pr_vdebug pr_debug -#endif /* pr_vdebug */ -# define ffs_dump_mem(prefix, ptr, len) \ - print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len) -#else -#ifndef pr_vdebug -# define pr_vdebug(...) do { } while (0) -#endif /* pr_vdebug */ -# define ffs_dump_mem(prefix, ptr, len) do { } while (0) -#endif /* VERBOSE_DEBUG */ - -#define ENTER() pr_vdebug("%s()\n", __func__) - - -/* The data structure and setup file ****************************************/ - -enum ffs_state { - /* - * Waiting for descriptors and strings. - * - * In this state no open(2), read(2) or write(2) on epfiles - * may succeed (which should not be the problem as there - * should be no such files opened in the first place). - */ - FFS_READ_DESCRIPTORS, - FFS_READ_STRINGS, - - /* - * We've got descriptors and strings. We are or have called - * ffs_ready(). functionfs_bind() may have - * been called but we don't know. - * - * This is the only state in which operations on epfiles may - * succeed. - */ - FFS_ACTIVE, - - /* - * All endpoints have been closed. This state is also set if - * we encounter an unrecoverable error. The only - * unrecoverable error is situation when after reading strings - * from user space we fail to initialise epfiles or - * ffs_ready() returns with error (<0). - * - * In this state no open(2), read(2) or write(2) (both on ep0 - * as well as epfile) may succeed (at this point epfiles are - * unlinked and all closed so this is not a problem; ep0 is - * also closed but ep0 file exists and so open(2) on ep0 must - * fail). - */ - FFS_CLOSING -}; - - -enum ffs_setup_state { - /* There is no setup request pending. */ - FFS_NO_SETUP, - /* - * User has read events and there was a setup request event - * there. The next read/write on ep0 will handle the - * request. - */ - FFS_SETUP_PENDING, - /* - * There was event pending but before user space handled it - * some other event was introduced which canceled existing - * setup. If this state is set read/write on ep0 return - * -EIDRM. This state is only set when adding event. - */ - FFS_SETUP_CANCELED -}; - - - -struct ffs_epfile; -struct ffs_function; - -struct ffs_data { - struct usb_gadget *gadget; - - /* - * Protect access read/write operations, only one read/write - * at a time. As a consequence protects ep0req and company. - * While setup request is being processed (queued) this is - * held. - */ - struct mutex mutex; - - /* - * Protect access to endpoint related structures (basically - * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for - * endpoint zero. - */ - spinlock_t eps_lock; - - /* - * XXX REVISIT do we need our own request? Since we are not - * handling setup requests immediately user space may be so - * slow that another setup will be sent to the gadget but this - * time not to us but another function and then there could be - * a race. Is that the case? Or maybe we can use cdev->req - * after all, maybe we just need some spinlock for that? - */ - struct usb_request *ep0req; /* P: mutex */ - struct completion ep0req_completion; /* P: mutex */ - int ep0req_status; /* P: mutex */ - - /* reference counter */ - atomic_t ref; - /* how many files are opened (EP0 and others) */ - atomic_t opened; - - /* EP0 state */ - enum ffs_state state; - - /* - * Possible transitions: - * + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock - * happens only in ep0 read which is P: mutex - * + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock - * happens only in ep0 i/o which is P: mutex - * + FFS_SETUP_PENDING -> FFS_SETUP_CANCELED -- P: ev.waitq.lock - * + FFS_SETUP_CANCELED -> FFS_NO_SETUP -- cmpxchg - */ - enum ffs_setup_state setup_state; - -#define FFS_SETUP_STATE(ffs) \ - ((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state, \ - FFS_SETUP_CANCELED, FFS_NO_SETUP)) - - /* Events & such. */ - struct { - u8 types[4]; - unsigned short count; - /* XXX REVISIT need to update it in some places, or do we? */ - unsigned short can_stall; - struct usb_ctrlrequest setup; - - wait_queue_head_t waitq; - } ev; /* the whole structure, P: ev.waitq.lock */ - - /* Flags */ - unsigned long flags; -#define FFS_FL_CALL_CLOSED_CALLBACK 0 -#define FFS_FL_BOUND 1 - - /* Active function */ - struct ffs_function *func; - - /* - * Device name, write once when file system is mounted. - * Intended for user to read if she wants. - */ - const char *dev_name; - /* Private data for our user (ie. gadget). Managed by user. */ - void *private_data; - - /* filled by __ffs_data_got_descs() */ - /* - * Real descriptors are 16 bytes after raw_descs (so you need - * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the - * first full speed descriptor). raw_descs_length and - * raw_fs_descs_length do not have those 16 bytes added. - */ - const void *raw_descs; - unsigned raw_descs_length; - unsigned raw_fs_descs_length; - unsigned fs_descs_count; - unsigned hs_descs_count; - - unsigned short strings_count; - unsigned short interfaces_count; - unsigned short eps_count; - unsigned short _pad1; - - /* filled by __ffs_data_got_strings() */ - /* ids in stringtabs are set in functionfs_bind() */ - const void *raw_strings; - struct usb_gadget_strings **stringtabs; - - /* - * File system's super block, write once when file system is - * mounted. - */ - struct super_block *sb; - - /* File permissions, written once when fs is mounted */ - struct ffs_file_perms { - umode_t mode; - kuid_t uid; - kgid_t gid; - } file_perms; - - /* - * The endpoint files, filled by ffs_epfiles_create(), - * destroyed by ffs_epfiles_destroy(). - */ - struct ffs_epfile *epfiles; -}; - /* Reference counter handling */ static void ffs_data_get(struct ffs_data *ffs); static void ffs_data_put(struct ffs_data *ffs); @@ -300,15 +97,19 @@ static struct ffs_function *ffs_func_from_usb(struct usb_function *f) return container_of(f, struct ffs_function, function); } +#ifdef USB_FFS_INCLUDED static void ffs_func_free(struct ffs_function *func); +#endif static void ffs_func_eps_disable(struct ffs_function *func); static int __must_check ffs_func_eps_enable(struct ffs_function *func); static int ffs_func_bind(struct usb_configuration *, struct usb_function *); -static void ffs_func_unbind(struct usb_configuration *, +#ifdef USB_FFS_INCLUDED +static void old_ffs_func_unbind(struct usb_configuration *, struct usb_function *); +#endif static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned); static void ffs_func_disable(struct usb_function *); static int ffs_func_setup(struct usb_function *, @@ -364,6 +165,9 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data, /* Devices management *******************************************************/ DEFINE_MUTEX(ffs_lock); +#ifndef USB_FFS_INCLUDED +EXPORT_SYMBOL(ffs_lock); +#endif static struct ffs_dev *ffs_find_dev(const char *name); static void *ffs_acquire_dev(const char *dev_name); @@ -1499,6 +1303,8 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) kfree(epfiles); } +#ifdef USB_FFS_INCLUDED + static int functionfs_bind_config(struct usb_composite_dev *cdev, struct usb_configuration *c, struct ffs_data *ffs) @@ -1516,7 +1322,7 @@ static int functionfs_bind_config(struct usb_composite_dev *cdev, func->function.strings = ffs->stringtabs; func->function.bind = ffs_func_bind; - func->function.unbind = ffs_func_unbind; + func->function.unbind = old_ffs_func_unbind; func->function.set_alt = ffs_func_set_alt; func->function.disable = ffs_func_disable; func->function.setup = ffs_func_setup; @@ -1565,6 +1371,8 @@ static void ffs_func_free(struct ffs_function *func) kfree(func); } +#endif + static void ffs_func_eps_disable(struct ffs_function *func) { struct ffs_ep *ep = func->eps; @@ -2227,8 +2035,59 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, return 0; } -static int ffs_func_bind(struct usb_configuration *c, - struct usb_function *f) +#ifndef USB_FFS_INCLUDED +static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, + struct usb_configuration *c) +{ + struct ffs_function *func = ffs_func_from_usb(f); + struct f_fs_opts *ffs_opts = + container_of(f->fi, struct f_fs_opts, func_inst); + int ret; + + ENTER(); + + /* + * Legacy gadget triggers binding in functionfs_ready_callback, + * which already uses locking; taking the same lock here would + * cause a deadlock. + * + * Configfs-enabled gadgets however do need ffs_dev_lock. + */ + if (!ffs_opts->no_configfs) + ffs_dev_lock(); + ret = ffs_opts->dev->desc_ready ? 0 : -ENODEV; + func->ffs = ffs_opts->dev->ffs_data; + if (!ffs_opts->no_configfs) + ffs_dev_unlock(); + if (ret) + return ERR_PTR(ret); + + func->conf = c; + func->gadget = c->cdev->gadget; + + ffs_data_get(func->ffs); + + /* + * in drivers/usb/gadget/configfs.c:configfs_composite_bind() + * configurations are bound in sequence with list_for_each_entry, + * in each configuration its functions are bound in sequence + * with list_for_each_entry, so we assume no race condition + * with regard to ffs_opts->bound access + */ + if (!ffs_opts->refcnt) { + ret = functionfs_bind(func->ffs, c->cdev); + if (ret) + return ERR_PTR(ret); + } + ffs_opts->refcnt++; + func->function.strings = func->ffs->stringtabs; + + return ffs_opts; +} +#endif + +static int _ffs_func_bind(struct usb_configuration *c, + struct usb_function *f) { struct ffs_function *func = ffs_func_from_usb(f); struct ffs_data *ffs = func->ffs; @@ -2328,10 +2187,25 @@ error: return ret; } +static int ffs_func_bind(struct usb_configuration *c, + struct usb_function *f) +{ +#ifndef USB_FFS_INCLUDED + struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c); + + if (IS_ERR(ffs_opts)) + return PTR_ERR(ffs_opts); +#endif + + return _ffs_func_bind(c, f); +} + /* Other USB function hooks *************************************************/ -static void ffs_func_unbind(struct usb_configuration *c, +#ifdef USB_FFS_INCLUDED + +static void old_ffs_func_unbind(struct usb_configuration *c, struct usb_function *f) { struct ffs_function *func = ffs_func_from_usb(f); @@ -2349,6 +2223,8 @@ static void ffs_func_unbind(struct usb_configuration *c, ffs_func_free(func); } +#endif + static int ffs_func_set_alt(struct usb_function *f, unsigned interface, unsigned alt) { @@ -2523,6 +2399,116 @@ static struct ffs_dev *ffs_find_dev(const char *name) return _ffs_find_dev(name); } +/* Function registration interface ******************************************/ + +#ifndef USB_FFS_INCLUDED + +static void ffs_free_inst(struct usb_function_instance *f) +{ + struct f_fs_opts *opts; + + opts = to_f_fs_opts(f); + ffs_dev_lock(); + ffs_free_dev(opts->dev); + ffs_dev_unlock(); + kfree(opts); +} + +static struct usb_function_instance *ffs_alloc_inst(void) +{ + struct f_fs_opts *opts; + struct ffs_dev *dev; + + opts = kzalloc(sizeof(*opts), GFP_KERNEL); + if (!opts) + return ERR_PTR(-ENOMEM); + + opts->func_inst.free_func_inst = ffs_free_inst; + ffs_dev_lock(); + dev = ffs_alloc_dev(); + ffs_dev_unlock(); + if (IS_ERR(dev)) { + kfree(opts); + return ERR_CAST(dev); + } + opts->dev = dev; + + return &opts->func_inst; +} + +static void ffs_free(struct usb_function *f) +{ + kfree(ffs_func_from_usb(f)); +} + +static void ffs_func_unbind(struct usb_configuration *c, + struct usb_function *f) +{ + struct ffs_function *func = ffs_func_from_usb(f); + struct ffs_data *ffs = func->ffs; + struct f_fs_opts *opts = + container_of(f->fi, struct f_fs_opts, func_inst); + struct ffs_ep *ep = func->eps; + unsigned count = ffs->eps_count; + unsigned long flags; + + ENTER(); + if (ffs->func == func) { + ffs_func_eps_disable(func); + ffs->func = NULL; + } + + if (!--opts->refcnt) + functionfs_unbind(ffs); + + /* cleanup after autoconfig */ + spin_lock_irqsave(&func->ffs->eps_lock, flags); + do { + if (ep->ep && ep->req) + usb_ep_free_request(ep->ep, ep->req); + ep->req = NULL; + ++ep; + } while (--count); + spin_unlock_irqrestore(&func->ffs->eps_lock, flags); + kfree(func->eps); + func->eps = NULL; + /* + * eps, descriptors and interfaces_nums are allocated in the + * same chunk so only one free is required. + */ + func->function.fs_descriptors = NULL; + func->function.hs_descriptors = NULL; + func->interfaces_nums = NULL; + + ffs_event_add(ffs, FUNCTIONFS_UNBIND); +} + +static struct usb_function *ffs_alloc(struct usb_function_instance *fi) +{ + struct ffs_function *func; + + ENTER(); + + func = kzalloc(sizeof(*func), GFP_KERNEL); + if (unlikely(!func)) + return ERR_PTR(-ENOMEM); + + func->function.name = "Function FS Gadget"; + + func->function.bind = ffs_func_bind; + func->function.unbind = ffs_func_unbind; + func->function.set_alt = ffs_func_set_alt; + func->function.disable = ffs_func_disable; + func->function.setup = ffs_func_setup; + func->function.suspend = ffs_func_suspend; + func->function.resume = ffs_func_resume; + func->function.free_func = ffs_free; + + return &func->function; +} + +#endif + /* * ffs_lock must be taken by the caller of this function */ @@ -2581,6 +2567,9 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name) return ret; } +#ifndef USB_FFS_INCLUDED +EXPORT_SYMBOL(ffs_name_dev); +#endif int ffs_single_dev(struct ffs_dev *dev) { @@ -2597,6 +2586,9 @@ int ffs_single_dev(struct ffs_dev *dev) ffs_dev_unlock(); return ret; } +#ifndef USB_FFS_INCLUDED +EXPORT_SYMBOL(ffs_single_dev); +#endif /* * ffs_lock must be taken by the caller of this function @@ -2621,6 +2613,9 @@ static void *ffs_acquire_dev(const char *dev_name) ffs_dev = ERR_PTR(-ENODEV); else if (ffs_dev->mounted) ffs_dev = ERR_PTR(-EBUSY); + else if (ffs_dev->ffs_acquire_dev_callback && + ffs_dev->ffs_acquire_dev_callback(ffs_dev)) + ffs_dev = ERR_PTR(-ENODEV); else ffs_dev->mounted = true; @@ -2638,6 +2633,9 @@ static void ffs_release_dev(struct ffs_data *ffs_data) ffs_dev = ffs_data->private_data; if (ffs_dev) ffs_dev->mounted = false; + + if (ffs_dev->ffs_release_dev_callback) + ffs_dev->ffs_release_dev_callback(ffs_dev); ffs_dev_unlock(); } @@ -2720,3 +2718,9 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len) return data; } + +#ifndef USB_FFS_INCLUDED +DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Michal Nazarewicz"); +#endif diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index 074df0d56255..ffde36f2c672 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -54,6 +54,7 @@ static struct usb_function *f_rndis; # endif #endif +#define USB_FFS_INCLUDED #include "f_fs.c" #define DRIVER_NAME "g_ffs" diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h index 2d00f9d296a3..d60a9ddc0332 100644 --- a/drivers/usb/gadget/u_fs.h +++ b/drivers/usb/gadget/u_fs.h @@ -20,6 +20,22 @@ #include #include +#ifdef VERBOSE_DEBUG +#ifndef pr_vdebug +# define pr_vdebug pr_debug +#endif /* pr_vdebug */ +# define ffs_dump_mem(prefix, ptr, len) \ + print_hex_dump_bytes(pr_fmt(prefix ": "), DUMP_PREFIX_NONE, ptr, len) +#else +#ifndef pr_vdebug +# define pr_vdebug(...) do { } while (0) +#endif /* pr_vdebug */ +# define ffs_dump_mem(prefix, ptr, len) do { } while (0) +#endif /* VERBOSE_DEBUG */ + +#define ENTER() pr_vdebug("%s()\n", __func__) + + struct ffs_dev { const char *name; bool mounted; @@ -30,6 +46,8 @@ struct ffs_dev { int (*ffs_ready_callback)(struct ffs_data *ffs); void (*ffs_closed_callback)(struct ffs_data *ffs); + void *(*ffs_acquire_dev_callback)(struct ffs_dev *dev); + void (*ffs_release_dev_callback)(struct ffs_dev *dev); }; extern struct mutex ffs_lock; @@ -49,4 +67,200 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name); int ffs_single_dev(struct ffs_dev *dev); void ffs_free_dev(struct ffs_dev *dev); +struct ffs_epfile; +struct ffs_function; + +enum ffs_state { + /* + * Waiting for descriptors and strings. + * + * In this state no open(2), read(2) or write(2) on epfiles + * may succeed (which should not be the problem as there + * should be no such files opened in the first place). + */ + FFS_READ_DESCRIPTORS, + FFS_READ_STRINGS, + + /* + * We've got descriptors and strings. We are or have called + * functionfs_ready_callback(). functionfs_bind() may have + * been called but we don't know. + * + * This is the only state in which operations on epfiles may + * succeed. + */ + FFS_ACTIVE, + + /* + * All endpoints have been closed. This state is also set if + * we encounter an unrecoverable error. The only + * unrecoverable error is situation when after reading strings + * from user space we fail to initialise epfiles or + * functionfs_ready_callback() returns with error (<0). + * + * In this state no open(2), read(2) or write(2) (both on ep0 + * as well as epfile) may succeed (at this point epfiles are + * unlinked and all closed so this is not a problem; ep0 is + * also closed but ep0 file exists and so open(2) on ep0 must + * fail). + */ + FFS_CLOSING +}; + +enum ffs_setup_state { + /* There is no setup request pending. */ + FFS_NO_SETUP, + /* + * User has read events and there was a setup request event + * there. The next read/write on ep0 will handle the + * request. + */ + FFS_SETUP_PENDING, + /* + * There was event pending but before user space handled it + * some other event was introduced which canceled existing + * setup. If this state is set read/write on ep0 return + * -EIDRM. This state is only set when adding event. + */ + FFS_SETUP_CANCELED +}; + +struct ffs_data { + struct usb_gadget *gadget; + + /* + * Protect access read/write operations, only one read/write + * at a time. As a consequence protects ep0req and company. + * While setup request is being processed (queued) this is + * held. + */ + struct mutex mutex; + + /* + * Protect access to endpoint related structures (basically + * usb_ep_queue(), usb_ep_dequeue(), etc. calls) except for + * endpoint zero. + */ + spinlock_t eps_lock; + + /* + * XXX REVISIT do we need our own request? Since we are not + * handling setup requests immediately user space may be so + * slow that another setup will be sent to the gadget but this + * time not to us but another function and then there could be + * a race. Is that the case? Or maybe we can use cdev->req + * after all, maybe we just need some spinlock for that? + */ + struct usb_request *ep0req; /* P: mutex */ + struct completion ep0req_completion; /* P: mutex */ + int ep0req_status; /* P: mutex */ + + /* reference counter */ + atomic_t ref; + /* how many files are opened (EP0 and others) */ + atomic_t opened; + + /* EP0 state */ + enum ffs_state state; + + /* + * Possible transitions: + * + FFS_NO_SETUP -> FFS_SETUP_PENDING -- P: ev.waitq.lock + * happens only in ep0 read which is P: mutex + * + FFS_SETUP_PENDING -> FFS_NO_SETUP -- P: ev.waitq.lock + * happens only in ep0 i/o which is P: mutex + * + FFS_SETUP_PENDING -> FFS_SETUP_CANCELED -- P: ev.waitq.lock + * + FFS_SETUP_CANCELED -> FFS_NO_SETUP -- cmpxchg + */ + enum ffs_setup_state setup_state; + +#define FFS_SETUP_STATE(ffs) \ + ((enum ffs_setup_state)cmpxchg(&(ffs)->setup_state, \ + FFS_SETUP_CANCELED, FFS_NO_SETUP)) + + /* Events & such. */ + struct { + u8 types[4]; + unsigned short count; + /* XXX REVISIT need to update it in some places, or do we? */ + unsigned short can_stall; + struct usb_ctrlrequest setup; + + wait_queue_head_t waitq; + } ev; /* the whole structure, P: ev.waitq.lock */ + + /* Flags */ + unsigned long flags; +#define FFS_FL_CALL_CLOSED_CALLBACK 0 +#define FFS_FL_BOUND 1 + + /* Active function */ + struct ffs_function *func; + + /* + * Device name, write once when file system is mounted. + * Intended for user to read if she wants. + */ + const char *dev_name; + /* Private data for our user (ie. gadget). Managed by user. */ + void *private_data; + + /* filled by __ffs_data_got_descs() */ + /* + * Real descriptors are 16 bytes after raw_descs (so you need + * to skip 16 bytes (ie. ffs->raw_descs + 16) to get to the + * first full speed descriptor). raw_descs_length and + * raw_fs_descs_length do not have those 16 bytes added. + */ + const void *raw_descs; + unsigned raw_descs_length; + unsigned raw_fs_descs_length; + unsigned fs_descs_count; + unsigned hs_descs_count; + + unsigned short strings_count; + unsigned short interfaces_count; + unsigned short eps_count; + unsigned short _pad1; + + /* filled by __ffs_data_got_strings() */ + /* ids in stringtabs are set in functionfs_bind() */ + const void *raw_strings; + struct usb_gadget_strings **stringtabs; + + /* + * File system's super block, write once when file system is + * mounted. + */ + struct super_block *sb; + + /* File permissions, written once when fs is mounted */ + struct ffs_file_perms { + umode_t mode; + kuid_t uid; + kgid_t gid; + } file_perms; + + /* + * The endpoint files, filled by ffs_epfiles_create(), + * destroyed by ffs_epfiles_destroy(). + */ + struct ffs_epfile *epfiles; +}; + + +#ifndef USB_FFS_INCLUDED +struct f_fs_opts { + struct usb_function_instance func_inst; + struct ffs_dev *dev; + unsigned refcnt; + bool no_configfs; +}; + +static inline struct f_fs_opts *to_f_fs_opts(struct usb_function_instance *fi) +{ + return container_of(fi, struct f_fs_opts, func_inst); +} +#endif + #endif /* U_FFS_H */ diff --git a/include/linux/usb/functionfs.h b/include/linux/usb/functionfs.h index 9c1e92620dfb..3448efbe56aa 100644 --- a/include/linux/usb/functionfs.h +++ b/include/linux/usb/functionfs.h @@ -3,6 +3,7 @@ #include +#ifdef USB_FFS_INCLUDED struct ffs_data; struct usb_composite_dev; @@ -20,3 +21,4 @@ static int functionfs_bind_config(struct usb_composite_dev *cdev, #endif +#endif -- cgit v1.2.3-59-g8ed1b From 3d8d72a4c3c844c3c770c153bf570dc843143ac0 Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 3 Dec 2013 15:15:35 +0100 Subject: usb: gadget: FunctionFS: Remove compatibility layer There are no old function interface users left, so the old interface can be removed. Signed-off-by: Andrzej Pietrasiewicz Signed-off-by: Kyungmin Park Acked-by: Michal Nazarewicz Signed-off-by: Felipe Balbi --- drivers/usb/gadget/f_fs.c | 114 ----------------------------------------- drivers/usb/gadget/u_fs.h | 2 - include/linux/usb/functionfs.h | 18 ------- 3 files changed, 134 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 8d318eaaaf20..9c8c74c25f1e 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -97,19 +97,12 @@ static struct ffs_function *ffs_func_from_usb(struct usb_function *f) return container_of(f, struct ffs_function, function); } -#ifdef USB_FFS_INCLUDED -static void ffs_func_free(struct ffs_function *func); -#endif static void ffs_func_eps_disable(struct ffs_function *func); static int __must_check ffs_func_eps_enable(struct ffs_function *func); static int ffs_func_bind(struct usb_configuration *, struct usb_function *); -#ifdef USB_FFS_INCLUDED -static void old_ffs_func_unbind(struct usb_configuration *, - struct usb_function *); -#endif static int ffs_func_set_alt(struct usb_function *, unsigned, unsigned); static void ffs_func_disable(struct usb_function *); static int ffs_func_setup(struct usb_function *, @@ -165,9 +158,7 @@ ffs_sb_create_file(struct super_block *sb, const char *name, void *data, /* Devices management *******************************************************/ DEFINE_MUTEX(ffs_lock); -#ifndef USB_FFS_INCLUDED EXPORT_SYMBOL(ffs_lock); -#endif static struct ffs_dev *ffs_find_dev(const char *name); static void *ffs_acquire_dev(const char *dev_name); @@ -1303,75 +1294,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) kfree(epfiles); } -#ifdef USB_FFS_INCLUDED - -static int functionfs_bind_config(struct usb_composite_dev *cdev, - struct usb_configuration *c, - struct ffs_data *ffs) -{ - struct ffs_function *func; - int ret; - - ENTER(); - - func = kzalloc(sizeof *func, GFP_KERNEL); - if (unlikely(!func)) - return -ENOMEM; - - func->function.name = "Function FS Gadget"; - func->function.strings = ffs->stringtabs; - - func->function.bind = ffs_func_bind; - func->function.unbind = old_ffs_func_unbind; - func->function.set_alt = ffs_func_set_alt; - func->function.disable = ffs_func_disable; - func->function.setup = ffs_func_setup; - func->function.suspend = ffs_func_suspend; - func->function.resume = ffs_func_resume; - - func->conf = c; - func->gadget = cdev->gadget; - func->ffs = ffs; - ffs_data_get(ffs); - - ret = usb_add_function(c, &func->function); - if (unlikely(ret)) - ffs_func_free(func); - - return ret; -} - -static void ffs_func_free(struct ffs_function *func) -{ - struct ffs_ep *ep = func->eps; - unsigned count = func->ffs->eps_count; - unsigned long flags; - - ENTER(); - - /* cleanup after autoconfig */ - spin_lock_irqsave(&func->ffs->eps_lock, flags); - do { - if (ep->ep && ep->req) - usb_ep_free_request(ep->ep, ep->req); - ep->req = NULL; - ++ep; - } while (--count); - spin_unlock_irqrestore(&func->ffs->eps_lock, flags); - - ffs_data_put(func->ffs); - - kfree(func->eps); - /* - * eps and interfaces_nums are allocated in the same chunk so - * only one free is required. Descriptors are also allocated - * in the same chunk. - */ - - kfree(func); -} - -#endif static void ffs_func_eps_disable(struct ffs_function *func) { @@ -2035,7 +1957,6 @@ static int __ffs_func_bind_do_nums(enum ffs_entity_type type, u8 *valuep, return 0; } -#ifndef USB_FFS_INCLUDED static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, struct usb_configuration *c) { @@ -2084,7 +2005,6 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, return ffs_opts; } -#endif static int _ffs_func_bind(struct usb_configuration *c, struct usb_function *f) @@ -2190,12 +2110,10 @@ error: static int ffs_func_bind(struct usb_configuration *c, struct usb_function *f) { -#ifndef USB_FFS_INCLUDED struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c); if (IS_ERR(ffs_opts)) return PTR_ERR(ffs_opts); -#endif return _ffs_func_bind(c, f); } @@ -2203,28 +2121,6 @@ static int ffs_func_bind(struct usb_configuration *c, /* Other USB function hooks *************************************************/ -#ifdef USB_FFS_INCLUDED - -static void old_ffs_func_unbind(struct usb_configuration *c, - struct usb_function *f) -{ - struct ffs_function *func = ffs_func_from_usb(f); - struct ffs_data *ffs = func->ffs; - - ENTER(); - - if (ffs->func == func) { - ffs_func_eps_disable(func); - ffs->func = NULL; - } - - ffs_event_add(ffs, FUNCTIONFS_UNBIND); - - ffs_func_free(func); -} - -#endif - static int ffs_func_set_alt(struct usb_function *f, unsigned interface, unsigned alt) { @@ -2401,8 +2297,6 @@ static struct ffs_dev *ffs_find_dev(const char *name) /* Function registration interface ******************************************/ -#ifndef USB_FFS_INCLUDED - static void ffs_free_inst(struct usb_function_instance *f) { struct f_fs_opts *opts; @@ -2507,8 +2401,6 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi) return &func->function; } -#endif - /* * ffs_lock must be taken by the caller of this function */ @@ -2567,9 +2459,7 @@ int ffs_name_dev(struct ffs_dev *dev, const char *name) return ret; } -#ifndef USB_FFS_INCLUDED EXPORT_SYMBOL(ffs_name_dev); -#endif int ffs_single_dev(struct ffs_dev *dev) { @@ -2586,9 +2476,7 @@ int ffs_single_dev(struct ffs_dev *dev) ffs_dev_unlock(); return ret; } -#ifndef USB_FFS_INCLUDED EXPORT_SYMBOL(ffs_single_dev); -#endif /* * ffs_lock must be taken by the caller of this function @@ -2719,8 +2607,6 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len) return data; } -#ifndef USB_FFS_INCLUDED DECLARE_USB_FUNCTION_INIT(ffs, ffs_alloc_inst, ffs_alloc); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michal Nazarewicz"); -#endif diff --git a/drivers/usb/gadget/u_fs.h b/drivers/usb/gadget/u_fs.h index d60a9ddc0332..09313750f913 100644 --- a/drivers/usb/gadget/u_fs.h +++ b/drivers/usb/gadget/u_fs.h @@ -249,7 +249,6 @@ struct ffs_data { }; -#ifndef USB_FFS_INCLUDED struct f_fs_opts { struct usb_function_instance func_inst; struct ffs_dev *dev; @@ -261,6 +260,5 @@ static inline struct f_fs_opts *to_f_fs_opts(struct usb_function_instance *fi) { return container_of(fi, struct f_fs_opts, func_inst); } -#endif #endif /* U_FFS_H */ diff --git a/include/linux/usb/functionfs.h b/include/linux/usb/functionfs.h index 3448efbe56aa..71190663f1ee 100644 --- a/include/linux/usb/functionfs.h +++ b/include/linux/usb/functionfs.h @@ -3,22 +3,4 @@ #include -#ifdef USB_FFS_INCLUDED - -struct ffs_data; -struct usb_composite_dev; -struct usb_configuration; - -static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) - __attribute__((warn_unused_result, nonnull)); -static void functionfs_unbind(struct ffs_data *ffs) - __attribute__((nonnull)); - -static int functionfs_bind_config(struct usb_composite_dev *cdev, - struct usb_configuration *c, - struct ffs_data *ffs) - __attribute__((warn_unused_result, nonnull)); - - -#endif #endif -- cgit v1.2.3-59-g8ed1b From ac7c8e3dd2ed6489be1f6bc722029fb4855c3a34 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 11 Oct 2013 10:17:39 -0700 Subject: rcu: Add comment on evaluate-once properties of rcu_assign_pointer(). The rcu_assign_pointer() macro, as with most cpp macros, must not evaluate its argument more than once. And it in fact does not. But this might not be obvious to the casual observer, because one of the arguments appears no less than three times. However, but one expansion is only visible to sparse (__CHECKER__), and one lives inside a typeof (where it will never be evaluated), so this is in fact safe. This commit therefore adds a comment making this explicit. Reported-by: Josh Triplett Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/rcupdate.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include/linux') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 39cbb889e20d..00ad28168ef0 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -911,6 +911,14 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) * rcu_assign_pointer() is a very bad thing that results in * impossible-to-diagnose memory corruption. So please be careful. * See the RCU_INIT_POINTER() comment header for details. + * + * Note that rcu_assign_pointer() evaluates each of its arguments only + * once, appearances notwithstanding. One of the "extra" evaluations + * is in typeof() and the other visible only to sparse (__CHECKER__), + * neither of which actually execute the argument. As with most cpp + * macros, this execute-arguments-only-once property is important, so + * please be careful when making changes to rcu_assign_pointer() and the + * other macros that it invokes. */ #define rcu_assign_pointer(p, v) \ __rcu_assign_pointer((p), (v), __rcu) -- cgit v1.2.3-59-g8ed1b From 9d162cd06349dfee6b4f254b3abf1355cf0aee43 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sun, 1 Sep 2013 16:42:52 -0700 Subject: rcu: Make rcu_assign_pointer's assignment volatile and type-safe The rcu_assign_pointer() primitive needs to use ACCESS_ONCE to make the assignment to the destination pointer volatile, to protect against compilers too clever for their own good. Signed-off-by: Josh Triplett Signed-off-by: Paul E. McKenney --- include/linux/rcupdate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 00ad28168ef0..97853cd2d7b4 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -551,7 +551,7 @@ static inline void rcu_preempt_sleep_check(void) #define __rcu_assign_pointer(p, v, space) \ do { \ smp_wmb(); \ - (p) = (typeof(*v) __force space *)(v); \ + ACCESS_ONCE(p) = (typeof(*(v)) __force space *)(v); \ } while (0) -- cgit v1.2.3-59-g8ed1b From 462225ae47d7175f886281d8a91708550cd5178c Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 11 Nov 2013 09:59:34 -0800 Subject: rcu: Add an RCU_INITIALIZER for global RCU-protected pointers There is currently no way to initialize a global RCU-protected pointer without either putting up with sparse complaints or open-coding an obscure cast. This commit therefore creates RCU_INITIALIZER(), which is intended to be used as follows: struct foo __rcu *p = RCU_INITIALIZER(&my_rcu_structure); This commit also applies RCU_INITIALIZER() to eliminate repeated open-coded obscure casts in __rcu_assign_pointer(), RCU_INIT_POINTER(), and RCU_POINTER_INITIALIZER(). This commit also inlines __rcu_assign_pointer() into its only caller, rcu_assign_pointer(). Suggested-by: Steven Rostedt Signed-off-by: Paul E. McKenney Reviewed-by: Josh Triplett --- include/linux/rcupdate.h | 80 +++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 38 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 97853cd2d7b4..ea3816cf1a13 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -548,10 +548,48 @@ static inline void rcu_preempt_sleep_check(void) smp_read_barrier_depends(); \ (_________p1); \ }) -#define __rcu_assign_pointer(p, v, space) \ + +/** + * RCU_INITIALIZER() - statically initialize an RCU-protected global variable + * @v: The value to statically initialize with. + */ +#define RCU_INITIALIZER(v) (typeof(*(v)) __force __rcu *)(v) + +/** + * rcu_assign_pointer() - assign to RCU-protected pointer + * @p: pointer to assign to + * @v: value to assign (publish) + * + * Assigns the specified value to the specified RCU-protected + * pointer, ensuring that any concurrent RCU readers will see + * any prior initialization. + * + * Inserts memory barriers on architectures that require them + * (which is most of them), and also prevents the compiler from + * reordering the code that initializes the structure after the pointer + * assignment. More importantly, this call documents which pointers + * will be dereferenced by RCU read-side code. + * + * In some special cases, you may use RCU_INIT_POINTER() instead + * of rcu_assign_pointer(). RCU_INIT_POINTER() is a bit faster due + * to the fact that it does not constrain either the CPU or the compiler. + * That said, using RCU_INIT_POINTER() when you should have used + * rcu_assign_pointer() is a very bad thing that results in + * impossible-to-diagnose memory corruption. So please be careful. + * See the RCU_INIT_POINTER() comment header for details. + * + * Note that rcu_assign_pointer() evaluates each of its arguments only + * once, appearances notwithstanding. One of the "extra" evaluations + * is in typeof() and the other visible only to sparse (__CHECKER__), + * neither of which actually execute the argument. As with most cpp + * macros, this execute-arguments-only-once property is important, so + * please be careful when making changes to rcu_assign_pointer() and the + * other macros that it invokes. + */ +#define rcu_assign_pointer(p, v) \ do { \ smp_wmb(); \ - ACCESS_ONCE(p) = (typeof(*(v)) __force space *)(v); \ + ACCESS_ONCE(p) = RCU_INITIALIZER(v); \ } while (0) @@ -889,40 +927,6 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) preempt_enable_notrace(); } -/** - * rcu_assign_pointer() - assign to RCU-protected pointer - * @p: pointer to assign to - * @v: value to assign (publish) - * - * Assigns the specified value to the specified RCU-protected - * pointer, ensuring that any concurrent RCU readers will see - * any prior initialization. - * - * Inserts memory barriers on architectures that require them - * (which is most of them), and also prevents the compiler from - * reordering the code that initializes the structure after the pointer - * assignment. More importantly, this call documents which pointers - * will be dereferenced by RCU read-side code. - * - * In some special cases, you may use RCU_INIT_POINTER() instead - * of rcu_assign_pointer(). RCU_INIT_POINTER() is a bit faster due - * to the fact that it does not constrain either the CPU or the compiler. - * That said, using RCU_INIT_POINTER() when you should have used - * rcu_assign_pointer() is a very bad thing that results in - * impossible-to-diagnose memory corruption. So please be careful. - * See the RCU_INIT_POINTER() comment header for details. - * - * Note that rcu_assign_pointer() evaluates each of its arguments only - * once, appearances notwithstanding. One of the "extra" evaluations - * is in typeof() and the other visible only to sparse (__CHECKER__), - * neither of which actually execute the argument. As with most cpp - * macros, this execute-arguments-only-once property is important, so - * please be careful when making changes to rcu_assign_pointer() and the - * other macros that it invokes. - */ -#define rcu_assign_pointer(p, v) \ - __rcu_assign_pointer((p), (v), __rcu) - /** * RCU_INIT_POINTER() - initialize an RCU protected pointer * @@ -957,7 +961,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) */ #define RCU_INIT_POINTER(p, v) \ do { \ - p = (typeof(*v) __force __rcu *)(v); \ + p = RCU_INITIALIZER(v); \ } while (0) /** @@ -966,7 +970,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) * GCC-style initialization for an RCU-protected pointer in a structure field. */ #define RCU_POINTER_INITIALIZER(p, v) \ - .p = (typeof(*v) __force __rcu *)(v) + .p = RCU_INITIALIZER(v) /* * Does the specified offset indicate that the corresponding rcu_head -- cgit v1.2.3-59-g8ed1b From 584dc4ce55267765b415a8517613d1207f1741e5 Mon Sep 17 00:00:00 2001 From: Teodora Baluta Date: Mon, 11 Nov 2013 17:11:23 +0200 Subject: rcu: Remove "extern" from function declarations in include/linux/*rcu*.h Function prototypes don't need to have the "extern" keyword since this is the default behavior. Its explicit use is redundant. This commit therefore removes them. Signed-off-by: Teodora Baluta Signed-off-by: Paul E. McKenney --- include/linux/rculist.h | 4 +-- include/linux/rcupdate.h | 80 ++++++++++++++++++++++++------------------------ include/linux/rcutiny.h | 2 +- include/linux/rcutree.h | 36 +++++++++++----------- 4 files changed, 61 insertions(+), 61 deletions(-) (limited to 'include/linux') diff --git a/include/linux/rculist.h b/include/linux/rculist.h index 45a0a9e81478..dbaf99084112 100644 --- a/include/linux/rculist.h +++ b/include/linux/rculist.h @@ -55,8 +55,8 @@ static inline void __list_add_rcu(struct list_head *new, next->prev = new; } #else -extern void __list_add_rcu(struct list_head *new, - struct list_head *prev, struct list_head *next); +void __list_add_rcu(struct list_head *new, + struct list_head *prev, struct list_head *next); #endif /** diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index a94a5805d378..52c1b13c4d76 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -50,13 +50,13 @@ extern int rcutorture_runnable; /* for sysctl */ #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */ #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) -extern void rcutorture_record_test_transition(void); -extern void rcutorture_record_progress(unsigned long vernum); -extern void do_trace_rcu_torture_read(const char *rcutorturename, - struct rcu_head *rhp, - unsigned long secs, - unsigned long c_old, - unsigned long c); +void rcutorture_record_test_transition(void); +void rcutorture_record_progress(unsigned long vernum); +void do_trace_rcu_torture_read(const char *rcutorturename, + struct rcu_head *rhp, + unsigned long secs, + unsigned long c_old, + unsigned long c); #else static inline void rcutorture_record_test_transition(void) { @@ -65,11 +65,11 @@ static inline void rcutorture_record_progress(unsigned long vernum) { } #ifdef CONFIG_RCU_TRACE -extern void do_trace_rcu_torture_read(const char *rcutorturename, - struct rcu_head *rhp, - unsigned long secs, - unsigned long c_old, - unsigned long c); +void do_trace_rcu_torture_read(const char *rcutorturename, + struct rcu_head *rhp, + unsigned long secs, + unsigned long c_old, + unsigned long c); #else #define do_trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \ do { } while (0) @@ -118,8 +118,8 @@ extern void do_trace_rcu_torture_read(const char *rcutorturename, * if CPU A and CPU B are the same CPU (but again only if the system has * more than one CPU). */ -extern void call_rcu(struct rcu_head *head, - void (*func)(struct rcu_head *head)); +void call_rcu(struct rcu_head *head, + void (*func)(struct rcu_head *head)); #else /* #ifdef CONFIG_PREEMPT_RCU */ @@ -149,8 +149,8 @@ extern void call_rcu(struct rcu_head *head, * See the description of call_rcu() for more detailed information on * memory ordering guarantees. */ -extern void call_rcu_bh(struct rcu_head *head, - void (*func)(struct rcu_head *head)); +void call_rcu_bh(struct rcu_head *head, + void (*func)(struct rcu_head *head)); /** * call_rcu_sched() - Queue an RCU for invocation after sched grace period. @@ -171,16 +171,16 @@ extern void call_rcu_bh(struct rcu_head *head, * See the description of call_rcu() for more detailed information on * memory ordering guarantees. */ -extern void call_rcu_sched(struct rcu_head *head, - void (*func)(struct rcu_head *rcu)); +void call_rcu_sched(struct rcu_head *head, + void (*func)(struct rcu_head *rcu)); -extern void synchronize_sched(void); +void synchronize_sched(void); #ifdef CONFIG_PREEMPT_RCU -extern void __rcu_read_lock(void); -extern void __rcu_read_unlock(void); -extern void rcu_read_unlock_special(struct task_struct *t); +void __rcu_read_lock(void); +void __rcu_read_unlock(void); +void rcu_read_unlock_special(struct task_struct *t); void synchronize_rcu(void); /* @@ -216,19 +216,19 @@ static inline int rcu_preempt_depth(void) #endif /* #else #ifdef CONFIG_PREEMPT_RCU */ /* Internal to kernel */ -extern void rcu_init(void); -extern void rcu_sched_qs(int cpu); -extern void rcu_bh_qs(int cpu); -extern void rcu_check_callbacks(int cpu, int user); +void rcu_init(void); +void rcu_sched_qs(int cpu); +void rcu_bh_qs(int cpu); +void rcu_check_callbacks(int cpu, int user); struct notifier_block; -extern void rcu_idle_enter(void); -extern void rcu_idle_exit(void); -extern void rcu_irq_enter(void); -extern void rcu_irq_exit(void); +void rcu_idle_enter(void); +void rcu_idle_exit(void); +void rcu_irq_enter(void); +void rcu_irq_exit(void); #ifdef CONFIG_RCU_USER_QS -extern void rcu_user_enter(void); -extern void rcu_user_exit(void); +void rcu_user_enter(void); +void rcu_user_exit(void); #else static inline void rcu_user_enter(void) { } static inline void rcu_user_exit(void) { } @@ -262,7 +262,7 @@ static inline void rcu_user_hooks_switch(struct task_struct *prev, } while (0) #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP) -extern bool __rcu_is_watching(void); +bool __rcu_is_watching(void); #endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP) */ /* @@ -289,8 +289,8 @@ void wait_rcu_gp(call_rcu_func_t crf); * initialization. */ #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD -extern void init_rcu_head_on_stack(struct rcu_head *head); -extern void destroy_rcu_head_on_stack(struct rcu_head *head); +void init_rcu_head_on_stack(struct rcu_head *head); +void destroy_rcu_head_on_stack(struct rcu_head *head); #else /* !CONFIG_DEBUG_OBJECTS_RCU_HEAD */ static inline void init_rcu_head_on_stack(struct rcu_head *head) { @@ -363,7 +363,7 @@ static inline int rcu_read_lock_held(void) * rcu_read_lock_bh_held() is defined out of line to avoid #include-file * hell. */ -extern int rcu_read_lock_bh_held(void); +int rcu_read_lock_bh_held(void); /** * rcu_read_lock_sched_held() - might we be in RCU-sched read-side critical section? @@ -449,7 +449,7 @@ static inline int rcu_read_lock_sched_held(void) #ifdef CONFIG_PROVE_RCU -extern int rcu_my_thread_group_empty(void); +int rcu_my_thread_group_empty(void); /** * rcu_lockdep_assert - emit lockdep splat if specified condition not met @@ -1006,7 +1006,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void) __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head)) #ifdef CONFIG_RCU_NOCB_CPU -extern bool rcu_is_nocb_cpu(int cpu); +bool rcu_is_nocb_cpu(int cpu); #else static inline bool rcu_is_nocb_cpu(int cpu) { return false; } #endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */ @@ -1014,8 +1014,8 @@ static inline bool rcu_is_nocb_cpu(int cpu) { return false; } /* Only for use by adaptive-ticks code. */ #ifdef CONFIG_NO_HZ_FULL_SYSIDLE -extern bool rcu_sys_is_idle(void); -extern void rcu_sysidle_force_exit(void); +bool rcu_sys_is_idle(void); +void rcu_sysidle_force_exit(void); #else /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */ static inline bool rcu_sys_is_idle(void) diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h index 09ebcbe9fd78..6f01771b571c 100644 --- a/include/linux/rcutiny.h +++ b/include/linux/rcutiny.h @@ -125,7 +125,7 @@ static inline void exit_rcu(void) #ifdef CONFIG_DEBUG_LOCK_ALLOC extern int rcu_scheduler_active __read_mostly; -extern void rcu_scheduler_starting(void); +void rcu_scheduler_starting(void); #else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ static inline void rcu_scheduler_starting(void) { diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h index 4b9c81548742..72137ee8c603 100644 --- a/include/linux/rcutree.h +++ b/include/linux/rcutree.h @@ -30,9 +30,9 @@ #ifndef __LINUX_RCUTREE_H #define __LINUX_RCUTREE_H -extern void rcu_note_context_switch(int cpu); -extern int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies); -extern void rcu_cpu_stall_reset(void); +void rcu_note_context_switch(int cpu); +int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies); +void rcu_cpu_stall_reset(void); /* * Note a virtualization-based context switch. This is simply a @@ -44,9 +44,9 @@ static inline void rcu_virt_note_context_switch(int cpu) rcu_note_context_switch(cpu); } -extern void synchronize_rcu_bh(void); -extern void synchronize_sched_expedited(void); -extern void synchronize_rcu_expedited(void); +void synchronize_rcu_bh(void); +void synchronize_sched_expedited(void); +void synchronize_rcu_expedited(void); void kfree_call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)); @@ -71,25 +71,25 @@ static inline void synchronize_rcu_bh_expedited(void) synchronize_sched_expedited(); } -extern void rcu_barrier(void); -extern void rcu_barrier_bh(void); -extern void rcu_barrier_sched(void); +void rcu_barrier(void); +void rcu_barrier_bh(void); +void rcu_barrier_sched(void); extern unsigned long rcutorture_testseq; extern unsigned long rcutorture_vernum; -extern long rcu_batches_completed(void); -extern long rcu_batches_completed_bh(void); -extern long rcu_batches_completed_sched(void); +long rcu_batches_completed(void); +long rcu_batches_completed_bh(void); +long rcu_batches_completed_sched(void); -extern void rcu_force_quiescent_state(void); -extern void rcu_bh_force_quiescent_state(void); -extern void rcu_sched_force_quiescent_state(void); +void rcu_force_quiescent_state(void); +void rcu_bh_force_quiescent_state(void); +void rcu_sched_force_quiescent_state(void); -extern void exit_rcu(void); +void exit_rcu(void); -extern void rcu_scheduler_starting(void); +void rcu_scheduler_starting(void); extern int rcu_scheduler_active __read_mostly; -extern bool rcu_is_watching(void); +bool rcu_is_watching(void); #endif /* __LINUX_RCUTREE_H */ -- cgit v1.2.3-59-g8ed1b From 10cdfe9f327ab8d120cf6957e58c6203e3a53847 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 6 Nov 2013 13:14:19 +0100 Subject: clk: shmobile: Add R-Car Gen2 clocks support The R-Car Gen2 SoCs (R8A7790 and R8A7791) have several clocks that are too custom to be supported in a generic driver. Those clocks can be divided in two categories: - Fixed rate clocks with multiplier and divisor set according to boot mode configuration - Custom divider clocks with SoC-specific divider values This driver supports both. Signed-off-by: Laurent Pinchart Acked-by: Kumar Gala Signed-off-by: Mike Turquette --- .../clock/renesas,rcar-gen2-cpg-clocks.txt | 32 +++ drivers/clk/Makefile | 1 + drivers/clk/shmobile/Makefile | 5 + drivers/clk/shmobile/clk-rcar-gen2.c | 298 +++++++++++++++++++++ include/linux/clk/shmobile.h | 19 ++ 5 files changed, 355 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt create mode 100644 drivers/clk/shmobile/Makefile create mode 100644 drivers/clk/shmobile/clk-rcar-gen2.c create mode 100644 include/linux/clk/shmobile.h (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt new file mode 100644 index 000000000000..7b41c2fe54db --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,rcar-gen2-cpg-clocks.txt @@ -0,0 +1,32 @@ +* Renesas R-Car Gen2 Clock Pulse Generator (CPG) + +The CPG generates core clocks for the R-Car Gen2 SoCs. It includes three PLLs +and several fixed ratio dividers. + +Required Properties: + + - compatible: Must be one of + - "renesas,r8a7790-cpg-clocks" for the r8a7790 CPG + - "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG + - "renesas,rcar-gen2-cpg-clocks" for the generic R-Car Gen2 CPG + + - reg: Base address and length of the memory resource used by the CPG + + - clocks: Reference to the parent clock + - #clock-cells: Must be 1 + - clock-output-names: The names of the clocks. Supported clocks are "main", + "pll0", "pll1", "pll3", "lb", "qspi", "sdh", "sd0", "sd1" and "z" + + +Example +------- + + cpg_clocks: cpg_clocks@e6150000 { + compatible = "renesas,r8a7790-cpg-clocks", + "renesas,rcar-gen2-cpg-clocks"; + reg = <0 0xe6150000 0 0x1000>; + clocks = <&extal_clk>; + #clock-cells = <1>; + clock-output-names = "main", "pll0, "pll1", "pll3", + "lb", "qspi", "sdh", "sd0", "sd1", "z"; + }; diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 7a10bc9a23e7..8dd1339be98b 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_PLAT_SAMSUNG) += samsung/ obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ +obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += shmobile/ obj-$(CONFIG_X86) += x86/ diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile new file mode 100644 index 000000000000..d0a9034a7946 --- /dev/null +++ b/drivers/clk/shmobile/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o +obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o + +# for emply built-in.o +obj-n := dummy diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c new file mode 100644 index 000000000000..a59ec217a124 --- /dev/null +++ b/drivers/clk/shmobile/clk-rcar-gen2.c @@ -0,0 +1,298 @@ +/* + * rcar_gen2 Core CPG Clocks + * + * Copyright (C) 2013 Ideas On Board SPRL + * + * Contact: Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct rcar_gen2_cpg { + struct clk_onecell_data data; + spinlock_t lock; + void __iomem *reg; +}; + +#define CPG_SDCKCR 0x00000074 +#define CPG_PLL0CR 0x000000d8 +#define CPG_FRQCRC 0x000000e0 +#define CPG_FRQCRC_ZFC_MASK (0x1f << 8) +#define CPG_FRQCRC_ZFC_SHIFT 8 + +/* ----------------------------------------------------------------------------- + * Z Clock + * + * Traits of this clock: + * prepare - clk_prepare only ensures that parents are prepared + * enable - clk_enable only ensures that parents are enabled + * rate - rate is adjustable. clk->rate = parent->rate * mult / 32 + * parent - fixed parent. No clk_set_parent support + */ + +struct cpg_z_clk { + struct clk_hw hw; + void __iomem *reg; +}; + +#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw) + +static unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct cpg_z_clk *zclk = to_z_clk(hw); + unsigned int mult; + unsigned int val; + + val = (clk_readl(zclk->reg) & CPG_FRQCRC_ZFC_MASK) + >> CPG_FRQCRC_ZFC_SHIFT; + mult = 32 - val; + + return div_u64((u64)parent_rate * mult, 32); +} + +static long cpg_z_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned long prate = *parent_rate; + unsigned int mult; + + if (!prate) + prate = 1; + + mult = div_u64((u64)rate * 32, prate); + mult = clamp(mult, 1U, 32U); + + return *parent_rate / 32 * mult; +} + +static int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct cpg_z_clk *zclk = to_z_clk(hw); + unsigned int mult; + u32 val; + + mult = div_u64((u64)rate * 32, parent_rate); + mult = clamp(mult, 1U, 32U); + + val = clk_readl(zclk->reg); + val &= ~CPG_FRQCRC_ZFC_MASK; + val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT; + clk_writel(val, zclk->reg); + + return 0; +} + +static const struct clk_ops cpg_z_clk_ops = { + .recalc_rate = cpg_z_clk_recalc_rate, + .round_rate = cpg_z_clk_round_rate, + .set_rate = cpg_z_clk_set_rate, +}; + +static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg) +{ + static const char *parent_name = "pll0"; + struct clk_init_data init; + struct cpg_z_clk *zclk; + struct clk *clk; + + zclk = kzalloc(sizeof(*zclk), GFP_KERNEL); + if (!zclk) + return ERR_PTR(-ENOMEM); + + init.name = "z"; + init.ops = &cpg_z_clk_ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + + zclk->reg = cpg->reg + CPG_FRQCRC; + zclk->hw.init = &init; + + clk = clk_register(NULL, &zclk->hw); + if (IS_ERR(clk)) + kfree(zclk); + + return clk; +} + +/* ----------------------------------------------------------------------------- + * CPG Clock Data + */ + +/* + * MD EXTAL PLL0 PLL1 PLL3 + * 14 13 19 (MHz) *1 *1 + *--------------------------------------------------- + * 0 0 0 15 x 1 x172/2 x208/2 x106 + * 0 0 1 15 x 1 x172/2 x208/2 x88 + * 0 1 0 20 x 1 x130/2 x156/2 x80 + * 0 1 1 20 x 1 x130/2 x156/2 x66 + * 1 0 0 26 / 2 x200/2 x240/2 x122 + * 1 0 1 26 / 2 x200/2 x240/2 x102 + * 1 1 0 30 / 2 x172/2 x208/2 x106 + * 1 1 1 30 / 2 x172/2 x208/2 x88 + * + * *1 : Table 7.6 indicates VCO ouput (PLLx = VCO/2) + */ +#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \ + (((md) & BIT(13)) >> 12) | \ + (((md) & BIT(19)) >> 19)) +struct cpg_pll_config { + unsigned int extal_div; + unsigned int pll1_mult; + unsigned int pll3_mult; +}; + +static const struct cpg_pll_config cpg_pll_configs[8] __initconst = { + { 1, 208, 106 }, { 1, 208, 88 }, { 1, 156, 80 }, { 1, 156, 66 }, + { 2, 240, 122 }, { 2, 240, 102 }, { 2, 208, 106 }, { 2, 208, 88 }, +}; + +/* SDHI divisors */ +static const struct clk_div_table cpg_sdh_div_table[] = { + { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, + { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, + { 8, 24 }, { 10, 36 }, { 11, 48 }, { 0, 0 }, +}; + +static const struct clk_div_table cpg_sd01_div_table[] = { + { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 }, + { 10, 36 }, { 11, 48 }, { 12, 10 }, { 0, 0 }, +}; + +/* ----------------------------------------------------------------------------- + * Initialization + */ + +static u32 cpg_mode __initdata; + +static struct clk * __init +rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg, + const struct cpg_pll_config *config, + const char *name) +{ + const struct clk_div_table *table = NULL; + const char *parent_name = "main"; + unsigned int shift; + unsigned int mult = 1; + unsigned int div = 1; + + if (!strcmp(name, "main")) { + parent_name = of_clk_get_parent_name(np, 0); + div = config->extal_div; + } else if (!strcmp(name, "pll0")) { + /* PLL0 is a configurable multiplier clock. Register it as a + * fixed factor clock for now as there's no generic multiplier + * clock implementation and we currently have no need to change + * the multiplier value. + */ + u32 value = clk_readl(cpg->reg + CPG_PLL0CR); + mult = ((value >> 24) & ((1 << 7) - 1)) + 1; + } else if (!strcmp(name, "pll1")) { + mult = config->pll1_mult / 2; + } else if (!strcmp(name, "pll3")) { + mult = config->pll3_mult; + } else if (!strcmp(name, "lb")) { + div = cpg_mode & BIT(18) ? 36 : 24; + } else if (!strcmp(name, "qspi")) { + div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2) + ? 16 : 20; + } else if (!strcmp(name, "sdh")) { + table = cpg_sdh_div_table; + shift = 8; + } else if (!strcmp(name, "sd0")) { + table = cpg_sd01_div_table; + shift = 4; + } else if (!strcmp(name, "sd1")) { + table = cpg_sd01_div_table; + shift = 0; + } else if (!strcmp(name, "z")) { + return cpg_z_clk_register(cpg); + } else { + return ERR_PTR(-EINVAL); + } + + if (!table) + return clk_register_fixed_factor(NULL, name, parent_name, 0, + mult, div); + else + return clk_register_divider_table(NULL, name, parent_name, 0, + cpg->reg + CPG_SDCKCR, shift, + 4, 0, table, &cpg->lock); +} + +static void __init rcar_gen2_cpg_clocks_init(struct device_node *np) +{ + const struct cpg_pll_config *config; + struct rcar_gen2_cpg *cpg; + struct clk **clks; + unsigned int i; + int num_clks; + + num_clks = of_property_count_strings(np, "clock-output-names"); + if (num_clks < 0) { + pr_err("%s: failed to count clocks\n", __func__); + return; + } + + cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); + clks = kzalloc(num_clks * sizeof(*clks), GFP_KERNEL); + if (cpg == NULL || clks == NULL) { + /* We're leaking memory on purpose, there's no point in cleaning + * up as the system won't boot anyway. + */ + pr_err("%s: failed to allocate cpg\n", __func__); + return; + } + + spin_lock_init(&cpg->lock); + + cpg->data.clks = clks; + cpg->data.clk_num = num_clks; + + cpg->reg = of_iomap(np, 0); + if (WARN_ON(cpg->reg == NULL)) + return; + + config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; + + for (i = 0; i < num_clks; ++i) { + const char *name; + struct clk *clk; + + of_property_read_string_index(np, "clock-output-names", i, + &name); + + clk = rcar_gen2_cpg_register_clock(np, cpg, config, name); + if (IS_ERR(clk)) + pr_err("%s: failed to register %s %s clock (%ld)\n", + __func__, np->name, name, PTR_ERR(clk)); + else + cpg->data.clks[i] = clk; + } + + of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); +} +CLK_OF_DECLARE(rcar_gen2_cpg_clks, "renesas,rcar-gen2-cpg-clocks", + rcar_gen2_cpg_clocks_init); + +void __init rcar_gen2_clocks_init(u32 mode) +{ + cpg_mode = mode; + + of_clk_init(NULL); +} diff --git a/include/linux/clk/shmobile.h b/include/linux/clk/shmobile.h new file mode 100644 index 000000000000..f9bf080a1123 --- /dev/null +++ b/include/linux/clk/shmobile.h @@ -0,0 +1,19 @@ +/* + * Copyright 2013 Ideas On Board SPRL + * + * Contact: Laurent Pinchart + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __LINUX_CLK_SHMOBILE_H_ +#define __LINUX_CLK_SHMOBILE_H_ + +#include + +void rcar_gen2_clocks_init(u32 mode); + +#endif -- cgit v1.2.3-59-g8ed1b From c08ac06ab3f3cdb8d34376c3a8a5e46a31a62c8f Mon Sep 17 00:00:00 2001 From: Takuya Yoshikawa Date: Fri, 13 Dec 2013 15:07:21 +0900 Subject: KVM: Use cond_resched() directly and remove useless kvm_resched() Since the commit 15ad7146 ("KVM: Use the scheduler preemption notifiers to make kvm preemptible"), the remaining stuff in this function is a simple cond_resched() call with an extra need_resched() check which was there to avoid dropping VCPUs unnecessarily. Now it is meaningless. Signed-off-by: Takuya Yoshikawa Signed-off-by: Paolo Bonzini --- arch/ia64/kvm/kvm-ia64.c | 2 +- arch/powerpc/kvm/book3s_hv.c | 2 +- arch/x86/kvm/x86.c | 2 +- include/linux/kvm_host.h | 1 - virt/kvm/kvm_main.c | 8 -------- 5 files changed, 3 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index 985bf80c622e..53f44bee9ebb 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c @@ -702,7 +702,7 @@ again: out: srcu_read_unlock(&vcpu->kvm->srcu, idx); if (r > 0) { - kvm_resched(vcpu); + cond_resched(); idx = srcu_read_lock(&vcpu->kvm->srcu); goto again; } diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 072287f1c3bc..3fa99b20894f 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -1348,7 +1348,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc) kvm_guest_exit(); preempt_enable(); - kvm_resched(vcpu); + cond_resched(); spin_lock(&vc->lock); now = get_tb(); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 21ef1ba184ae..4fb1ee619c1c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6125,7 +6125,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu) } if (need_resched()) { srcu_read_unlock(&kvm->srcu, vcpu->srcu_idx); - kvm_resched(vcpu); + cond_resched(); vcpu->srcu_idx = srcu_read_lock(&kvm->srcu); } } diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 9523d2ad7535..4ecf10775c4f 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -583,7 +583,6 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu); void kvm_vcpu_kick(struct kvm_vcpu *vcpu); bool kvm_vcpu_yield_to(struct kvm_vcpu *target); void kvm_vcpu_on_spin(struct kvm_vcpu *vcpu); -void kvm_resched(struct kvm_vcpu *vcpu); void kvm_load_guest_fpu(struct kvm_vcpu *vcpu); void kvm_put_guest_fpu(struct kvm_vcpu *vcpu); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index a0aa84b5941a..03c97e7ae4ca 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1710,14 +1710,6 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu) EXPORT_SYMBOL_GPL(kvm_vcpu_kick); #endif /* !CONFIG_S390 */ -void kvm_resched(struct kvm_vcpu *vcpu) -{ - if (!need_resched()) - return; - cond_resched(); -} -EXPORT_SYMBOL_GPL(kvm_resched); - bool kvm_vcpu_yield_to(struct kvm_vcpu *target) { struct pid *pid; -- cgit v1.2.3-59-g8ed1b From ac8344c4c0bf74c7efaf962cf2a6404331678ce4 Mon Sep 17 00:00:00 2001 From: DuanZhenzhong Date: Wed, 4 Dec 2013 13:09:16 +0800 Subject: PCI: Drop "irq" param from *_restore_msi_irqs() Change x86_msi.restore_msi_irqs(struct pci_dev *dev, int irq) to x86_msi.restore_msi_irqs(struct pci_dev *dev). restore_msi_irqs() restores multiple MSI-X IRQs, so param 'int irq' is unneeded. This makes code more consistent between vm and bare metal. Dom0 MSI-X restore code can also be optimized as XEN only has a hypercall to restore all MSI-X vectors at one time. Tested-by: Sucheta Chakraborty Signed-off-by: Zhenzhong Duan Signed-off-by: Bjorn Helgaas Acked-by: Konrad Rzeszutek Wilk --- arch/x86/include/asm/pci.h | 2 +- arch/x86/include/asm/x86_init.h | 2 +- arch/x86/kernel/x86_init.c | 4 ++-- arch/x86/pci/xen.c | 2 +- drivers/pci/msi.c | 19 ++++++++++++++----- include/linux/msi.h | 4 ++-- 6 files changed, 21 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h index 947b5c417e83..0de52c5bf9a2 100644 --- a/arch/x86/include/asm/pci.h +++ b/arch/x86/include/asm/pci.h @@ -104,7 +104,7 @@ extern void pci_iommu_alloc(void); struct msi_desc; int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); void native_teardown_msi_irq(unsigned int irq); -void native_restore_msi_irqs(struct pci_dev *dev, int irq); +void native_restore_msi_irqs(struct pci_dev *dev); int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, unsigned int irq_base, unsigned int irq_offset); #else diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index 0f1be11e43d2..e45e4da96bf1 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -181,7 +181,7 @@ struct x86_msi_ops { u8 hpet_id); void (*teardown_msi_irq)(unsigned int irq); void (*teardown_msi_irqs)(struct pci_dev *dev); - void (*restore_msi_irqs)(struct pci_dev *dev, int irq); + void (*restore_msi_irqs)(struct pci_dev *dev); int (*setup_hpet_msi)(unsigned int irq, unsigned int id); u32 (*msi_mask_irq)(struct msi_desc *desc, u32 mask, u32 flag); u32 (*msix_mask_irq)(struct msi_desc *desc, u32 flag); diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index 021783b1f46a..e48b674639cc 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c @@ -136,9 +136,9 @@ void arch_teardown_msi_irq(unsigned int irq) x86_msi.teardown_msi_irq(irq); } -void arch_restore_msi_irqs(struct pci_dev *dev, int irq) +void arch_restore_msi_irqs(struct pci_dev *dev) { - x86_msi.restore_msi_irqs(dev, irq); + x86_msi.restore_msi_irqs(dev); } u32 arch_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag) { diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index 5eee4959785d..103e702ec5a7 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -337,7 +337,7 @@ out: return ret; } -static void xen_initdom_restore_msi_irqs(struct pci_dev *dev, int irq) +static void xen_initdom_restore_msi_irqs(struct pci_dev *dev) { int ret = 0; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 3fcd67a16677..51bf0400a889 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -116,7 +116,7 @@ void __weak arch_teardown_msi_irqs(struct pci_dev *dev) return default_teardown_msi_irqs(dev); } -void default_restore_msi_irqs(struct pci_dev *dev, int irq) +static void default_restore_msi_irq(struct pci_dev *dev, int irq) { struct msi_desc *entry; @@ -134,9 +134,9 @@ void default_restore_msi_irqs(struct pci_dev *dev, int irq) write_msi_msg(irq, &entry->msg); } -void __weak arch_restore_msi_irqs(struct pci_dev *dev, int irq) +void __weak arch_restore_msi_irqs(struct pci_dev *dev) { - return default_restore_msi_irqs(dev, irq); + return default_restore_msi_irqs(dev); } static void msi_set_enable(struct pci_dev *dev, int enable) @@ -262,6 +262,15 @@ void unmask_msi_irq(struct irq_data *data) msi_set_mask_bit(data, 0); } +void default_restore_msi_irqs(struct pci_dev *dev) +{ + struct msi_desc *entry; + + list_for_each_entry(entry, &dev->msi_list, list) { + default_restore_msi_irq(dev, entry->irq); + } +} + void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg) { BUG_ON(entry->dev->current_state != PCI_D0); @@ -430,7 +439,7 @@ static void __pci_restore_msi_state(struct pci_dev *dev) pci_intx_for_msi(dev, 0); msi_set_enable(dev, 0); - arch_restore_msi_irqs(dev, dev->irq); + arch_restore_msi_irqs(dev); pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control); msi_mask_irq(entry, msi_capable_mask(control), entry->masked); @@ -455,8 +464,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev) control |= PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL; pci_write_config_word(dev, dev->msix_cap + PCI_MSIX_FLAGS, control); + arch_restore_msi_irqs(dev); list_for_each_entry(entry, &dev->msi_list, list) { - arch_restore_msi_irqs(dev, entry->irq); msix_mask_irq(entry, entry->masked); } diff --git a/include/linux/msi.h b/include/linux/msi.h index 009b02481436..92a2f991262a 100644 --- a/include/linux/msi.h +++ b/include/linux/msi.h @@ -60,10 +60,10 @@ void arch_teardown_msi_irq(unsigned int irq); int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); void arch_teardown_msi_irqs(struct pci_dev *dev); int arch_msi_check_device(struct pci_dev* dev, int nvec, int type); -void arch_restore_msi_irqs(struct pci_dev *dev, int irq); +void arch_restore_msi_irqs(struct pci_dev *dev); void default_teardown_msi_irqs(struct pci_dev *dev); -void default_restore_msi_irqs(struct pci_dev *dev, int irq); +void default_restore_msi_irqs(struct pci_dev *dev); u32 default_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag); u32 default_msix_mask_irq(struct msi_desc *desc, u32 flag); -- cgit v1.2.3-59-g8ed1b From d29adb34a94715174c88ca93e8aba955850c9bde Mon Sep 17 00:00:00 2001 From: Josh Durgin Date: Mon, 2 Dec 2013 19:11:48 -0800 Subject: libceph: block I/O when PAUSE or FULL osd map flags are set The PAUSEWR and PAUSERD flags are meant to stop the cluster from processing writes and reads, respectively. The FULL flag is set when the cluster determines that it is out of space, and will no longer process writes. PAUSEWR and PAUSERD are purely client-side settings already implemented in userspace clients. The osd does nothing special with these flags. When the FULL flag is set, however, the osd responds to all writes with -ENOSPC. For cephfs, this makes sense, but for rbd the block layer translates this into EIO. If a cluster goes from full to non-full quickly, a filesystem on top of rbd will not behave well, since some writes succeed while others get EIO. Fix this by blocking any writes when the FULL flag is set in the osd client. This is the same strategy used by userspace, so apply it by default. A follow-on patch makes this configurable. __map_request() is called to re-target osd requests in case the available osds changed. Add a paused field to a ceph_osd_request, and set it whenever an appropriate osd map flag is set. Avoid queueing paused requests in __map_request(), but force them to be resent if they become unpaused. Also subscribe to the next osd map from the monitor if any of these flags are set, so paused requests can be unblocked as soon as possible. Fixes: http://tracker.ceph.com/issues/6079 Reviewed-by: Sage Weil Signed-off-by: Josh Durgin --- include/linux/ceph/osd_client.h | 1 + net/ceph/osd_client.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ceph/osd_client.h b/include/linux/ceph/osd_client.h index 8f47625a0661..4fb6a8938957 100644 --- a/include/linux/ceph/osd_client.h +++ b/include/linux/ceph/osd_client.h @@ -138,6 +138,7 @@ struct ceph_osd_request { __le64 *r_request_pool; void *r_request_pgid; __le32 *r_request_attempts; + bool r_paused; struct ceph_eversion *r_request_reassert_version; int r_result; diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index a17eaae820f8..1ad9866dc707 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -1231,6 +1231,22 @@ void ceph_osdc_set_request_linger(struct ceph_osd_client *osdc, } EXPORT_SYMBOL(ceph_osdc_set_request_linger); +/* + * Returns whether a request should be blocked from being sent + * based on the current osdmap and osd_client settings. + * + * Caller should hold map_sem for read. + */ +static bool __req_should_be_paused(struct ceph_osd_client *osdc, + struct ceph_osd_request *req) +{ + bool pauserd = ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSERD); + bool pausewr = ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSEWR) || + ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL); + return (req->r_flags & CEPH_OSD_FLAG_READ && pauserd) || + (req->r_flags & CEPH_OSD_FLAG_WRITE && pausewr); +} + /* * Pick an osd (the first 'up' osd in the pg), allocate the osd struct * (as needed), and set the request r_osd appropriately. If there is @@ -1248,6 +1264,7 @@ static int __map_request(struct ceph_osd_client *osdc, int acting[CEPH_PG_MAX_SIZE]; int o = -1, num = 0; int err; + bool was_paused; dout("map_request %p tid %lld\n", req, req->r_tid); err = ceph_calc_ceph_pg(&pgid, req->r_oid, osdc->osdmap, @@ -1264,12 +1281,18 @@ static int __map_request(struct ceph_osd_client *osdc, num = err; } + was_paused = req->r_paused; + req->r_paused = __req_should_be_paused(osdc, req); + if (was_paused && !req->r_paused) + force_resend = 1; + if ((!force_resend && req->r_osd && req->r_osd->o_osd == o && req->r_sent >= req->r_osd->o_incarnation && req->r_num_pg_osds == num && memcmp(req->r_pg_osds, acting, sizeof(acting[0])*num) == 0) || - (req->r_osd == NULL && o == -1)) + (req->r_osd == NULL && o == -1) || + req->r_paused) return 0; /* no change */ dout("map_request tid %llu pgid %lld.%x osd%d (was osd%d)\n", @@ -1811,7 +1834,9 @@ done: * we find out when we are no longer full and stop returning * ENOSPC. */ - if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL)) + if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL) || + ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSERD) || + ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSEWR)) ceph_monc_request_next_osdmap(&osdc->client->monc); mutex_lock(&osdc->request_mutex); -- cgit v1.2.3-59-g8ed1b From 92e112fdbb3cb55b43390426501a7efacd893b96 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 13 Dec 2013 11:36:22 -0700 Subject: PCI/checkpatch: Deprecate DEFINE_PCI_DEVICE_TABLE Prefer use of the direct definition of struct pci_device_id instead of indirection via macro DEFINE_PCI_DEVICE_TABLE. Update the PCI documentation to deprecate DEFINE_PCI_DEVICE_TABLE. Update checkpatch adding --fix option. Signed-off-by: Joe Perches Signed-off-by: Bjorn Helgaas Reviewed-by: Jingoo Han --- Documentation/PCI/pci.txt | 6 ++++-- include/linux/pci.h | 3 +-- scripts/checkpatch.pl | 11 +++++++---- 3 files changed, 12 insertions(+), 8 deletions(-) (limited to 'include/linux') diff --git a/Documentation/PCI/pci.txt b/Documentation/PCI/pci.txt index 6f458564d625..9518006f6675 100644 --- a/Documentation/PCI/pci.txt +++ b/Documentation/PCI/pci.txt @@ -123,8 +123,10 @@ initialization with a pointer to a structure describing the driver The ID table is an array of struct pci_device_id entries ending with an -all-zero entry; use of the macro DEFINE_PCI_DEVICE_TABLE is the preferred -method of declaring the table. Each entry consists of: +all-zero entry. Definitions with static const are generally preferred. +Use of the deprecated macro DEFINE_PCI_DEVICE_TABLE should be avoided. + +Each entry consists of: vendor,device Vendor and device ID to match (or PCI_ANY_ID) diff --git a/include/linux/pci.h b/include/linux/pci.h index 1084a15175e0..88674b0947fb 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -634,8 +634,7 @@ struct pci_driver { * DEFINE_PCI_DEVICE_TABLE - macro used to describe a pci device table * @_table: device table name * - * This macro is used to create a struct pci_device_id array (a device table) - * in a generic manner. + * This macro is deprecated and should not be used in new code. */ #define DEFINE_PCI_DEVICE_TABLE(_table) \ const struct pci_device_id _table[] diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 9c9810030377..9fb30b15c9dc 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2634,10 +2634,13 @@ sub process { $herecurr); } -# check for declarations of struct pci_device_id - if ($line =~ /\bstruct\s+pci_device_id\s+\w+\s*\[\s*\]\s*\=\s*\{/) { - WARN("DEFINE_PCI_DEVICE_TABLE", - "Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\n" . $herecurr); +# check for uses of DEFINE_PCI_DEVICE_TABLE + if ($line =~ /\bDEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=/) { + if (WARN("DEFINE_PCI_DEVICE_TABLE", + "Prefer struct pci_device_id over deprecated DEFINE_PCI_DEVICE_TABLE\n" . $herecurr) && + $fix) { + $fixed[$linenr - 1] =~ s/\b(?:static\s+|)DEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=\s*/static const struct pci_device_id $1\[\] = /; + } } # check for new typedefs, only function parameters and sparse annotations -- cgit v1.2.3-59-g8ed1b From e001bfad913bf119fb67c1e8dd2d4ec1f5d392fa Mon Sep 17 00:00:00 2001 From: dingtianhong Date: Fri, 13 Dec 2013 10:19:55 +0800 Subject: bonding: create bond_first_slave_rcu() The bond_first_slave_rcu() will be used to instead of bond_first_slave() in rcu_read_lock(). According to the Jay Vosburgh's suggestion, the struct netdev_adjacent should hide from users who wanted to use it directly. so I package a new function to get the first slave of the bond. Suggested-by: Nikolay Aleksandrov Suggested-by: Jay Vosburgh Suggested-by: Veaceslav Falico Signed-off-by: Ding Tianhong Signed-off-by: David S. Miller --- drivers/net/bonding/bonding.h | 4 ++++ include/linux/netdevice.h | 1 + net/core/dev.c | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+) (limited to 'include/linux') diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 8283cbdec50a..8f0d6d0c383b 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -101,6 +101,10 @@ netdev_adjacent_get_private(bond_slave_list(bond)->prev) : \ NULL) +/* Caller must have rcu_read_lock */ +#define bond_first_slave_rcu(bond) \ + netdev_lower_get_first_private_rcu(bond->dev) + #define bond_is_first_slave(bond, pos) (pos == bond_first_slave(bond)) #define bond_is_last_slave(bond, pos) (pos == bond_last_slave(bond)) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 5260d2eae2e6..2c74d20dad34 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2907,6 +2907,7 @@ void *netdev_lower_get_next_private_rcu(struct net_device *dev, priv = netdev_lower_get_next_private_rcu(dev, &(iter))) void *netdev_adjacent_get_private(struct list_head *adj_list); +void *netdev_lower_get_first_private_rcu(struct net_device *dev); struct net_device *netdev_master_upper_dev_get(struct net_device *dev); struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev); int netdev_upper_dev_link(struct net_device *dev, struct net_device *upper_dev); diff --git a/net/core/dev.c b/net/core/dev.c index c95d664b2b42..9d4369ece679 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4543,6 +4543,27 @@ void *netdev_lower_get_next_private_rcu(struct net_device *dev, } EXPORT_SYMBOL(netdev_lower_get_next_private_rcu); +/** + * netdev_lower_get_first_private_rcu - Get the first ->private from the + * lower neighbour list, RCU + * variant + * @dev: device + * + * Gets the first netdev_adjacent->private from the dev's lower neighbour + * list. The caller must hold RCU read lock. + */ +void *netdev_lower_get_first_private_rcu(struct net_device *dev) +{ + struct netdev_adjacent *lower; + + lower = list_first_or_null_rcu(&dev->adj_list.lower, + struct netdev_adjacent, list); + if (lower) + return lower->private; + return NULL; +} +EXPORT_SYMBOL(netdev_lower_get_first_private_rcu); + /** * netdev_master_upper_dev_get_rcu - Get master upper device * @dev: device -- cgit v1.2.3-59-g8ed1b From cd72b8462a2ebbf9524e726c65c2770f0bf70d22 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Wed, 13 Nov 2013 22:55:24 +0800 Subject: dma: imx-sdma: Add sdma firmware version 2 support On i.MX5/6 series, SDMA is using new version firmware to support SSI dual FIFO feature and HDMI Audio (i.MX6Q/DL only). Thus add it. Signed-off-by: Nicolin Chen Acked-by: Sascha Hauer Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 15 ++++++++++++++- include/linux/platform_data/dma-imx-sdma.h | 5 +++++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index c75679d42028..f769c7383536 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -323,6 +323,7 @@ struct sdma_engine { struct clk *clk_ipg; struct clk *clk_ahb; spinlock_t channel_0_lock; + u32 script_number; struct sdma_script_start_addrs *script_addrs; const struct sdma_driver_data *drvdata; }; @@ -1238,6 +1239,7 @@ static void sdma_issue_pending(struct dma_chan *chan) } #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1 34 +#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2 38 static void sdma_add_scripts(struct sdma_engine *sdma, const struct sdma_script_start_addrs *addr) @@ -1246,7 +1248,7 @@ static void sdma_add_scripts(struct sdma_engine *sdma, s32 *saddr_arr = (u32 *)sdma->script_addrs; int i; - for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++) + for (i = 0; i < sdma->script_number; i++) if (addr_arr[i] > 0) saddr_arr[i] = addr_arr[i]; } @@ -1272,6 +1274,17 @@ static void sdma_load_firmware(const struct firmware *fw, void *context) goto err_firmware; if (header->ram_code_start + header->ram_code_size > fw->size) goto err_firmware; + switch (header->version_major) { + case 1: + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; + break; + case 2: + sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2; + break; + default: + dev_err(sdma->dev, "unknown firmware version\n"); + goto err_firmware; + } addr = (void *)header + header->script_addrs_start; ram_code = (void *)header + header->ram_code_start; diff --git a/include/linux/platform_data/dma-imx-sdma.h b/include/linux/platform_data/dma-imx-sdma.h index 3a3942823c20..eabac4e2fc99 100644 --- a/include/linux/platform_data/dma-imx-sdma.h +++ b/include/linux/platform_data/dma-imx-sdma.h @@ -43,6 +43,11 @@ struct sdma_script_start_addrs { s32 dptc_dvfs_addr; s32 utra_addr; s32 ram_code_start_addr; + /* End of v1 array */ + s32 mcu_2_ssish_addr; + s32 ssish_2_mcu_addr; + s32 hdmi_dma_addr; + /* End of v2 array */ }; /** -- cgit v1.2.3-59-g8ed1b From 1a895578d4e50577bb6aa79bd194b502f09dd768 Mon Sep 17 00:00:00 2001 From: Nicolin Chen Date: Wed, 13 Nov 2013 22:55:25 +0800 Subject: dma: imx-sdma: Add new dma type for ssi dual fifo script This patch adds a new DMA_TYPE for SSI dual FIFO script, included in SDMA firmware version 2. This script would allow SSI use dual fifo mode to transimit/receive data without occasional hardware underrun/overrun. Signed-off-by: Nicolin Chen Acked-by: Kumar Gala Acked-by: Sascha Hauer Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt | 1 + drivers/dma/imx-sdma.c | 4 ++++ include/linux/platform_data/dma-imx.h | 1 + 3 files changed, 6 insertions(+) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt index 4fa814d38321..68b83ecc3850 100644 --- a/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt +++ b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt @@ -42,6 +42,7 @@ The full ID of peripheral types can be found below. 19 IPU Memory 20 ASRC 21 ESAI + 22 SSI Dual FIFO (needs firmware ver >= 2) The third cell specifies the transfer priority as below. diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index f769c7383536..152247675feb 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -725,6 +725,10 @@ static void sdma_get_pc(struct sdma_channel *sdmac, per_2_emi = sdma->script_addrs->app_2_mcu_addr; emi_2_per = sdma->script_addrs->mcu_2_app_addr; break; + case IMX_DMATYPE_SSI_DUAL: + per_2_emi = sdma->script_addrs->ssish_2_mcu_addr; + emi_2_per = sdma->script_addrs->mcu_2_ssish_addr; + break; case IMX_DMATYPE_SSI_SP: case IMX_DMATYPE_MMC: case IMX_DMATYPE_SDHC: diff --git a/include/linux/platform_data/dma-imx.h b/include/linux/platform_data/dma-imx.h index beac6b8b6a7b..bcbc6c3c14c0 100644 --- a/include/linux/platform_data/dma-imx.h +++ b/include/linux/platform_data/dma-imx.h @@ -39,6 +39,7 @@ enum sdma_peripheral_type { IMX_DMATYPE_IPU_MEMORY, /* IPU Memory */ IMX_DMATYPE_ASRC, /* ASRC */ IMX_DMATYPE_ESAI, /* ESAI */ + IMX_DMATYPE_SSI_DUAL, /* SSI Dual FIFO */ }; enum imx_dma_prio { -- cgit v1.2.3-59-g8ed1b From 8ba3f4d00078e7a49c60c0bd6298f29402c3a0a0 Mon Sep 17 00:00:00 2001 From: Sherman Yin Date: Wed, 11 Dec 2013 10:37:17 -0800 Subject: pinctrl: Adds slew-rate, input-enable/disable This commit adds slew-rate and input-enable/disable support for pinconf -generic. Signed-off-by: Sherman Yin Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt | 3 +++ drivers/pinctrl/pinconf-generic.c | 4 ++++ include/linux/pinctrl/pinconf-generic.h | 4 ++++ 3 files changed, 11 insertions(+) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt index 1958ca9f9e5c..4414163e76d2 100644 --- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt +++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt @@ -151,6 +151,8 @@ drive-push-pull - drive actively high and low drive-open-drain - drive with open drain drive-open-source - drive with open source drive-strength - sink or source at most X mA +input-enable - enable input on pin (no effect on output) +input-disable - disable input on pin (no effect on output) input-schmitt-enable - enable schmitt-trigger mode input-schmitt-disable - disable schmitt-trigger mode input-debounce - debounce mode with debound time X @@ -158,6 +160,7 @@ low-power-enable - enable low power mode low-power-disable - disable low power mode output-low - set the pin to output mode with low level output-high - set the pin to output mode with high level +slew-rate - set the slew rate Some of the generic properties take arguments. For those that do, the arguments are described below. diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 55a0ebe830ac..3d9a999fb699 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -48,6 +48,7 @@ static struct pin_config_item conf_items[] = { PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL), PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA"), + PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL), PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL), PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec"), @@ -160,6 +161,8 @@ static struct pinconf_generic_dt_params dt_params[] = { { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 }, { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 }, { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 }, + { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 }, + { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 }, { "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 }, { "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 }, { "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 }, @@ -167,6 +170,7 @@ static struct pinconf_generic_dt_params dt_params[] = { { "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 }, { "output-low", PIN_CONFIG_OUTPUT, 0, }, { "output-high", PIN_CONFIG_OUTPUT, 1, }, + { "slew-rate", PIN_CONFIG_SLEW_RATE, 0}, }; /** diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index 282309d7c4dc..a15f10727eb8 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -61,6 +61,9 @@ * argument is ignored. * @PIN_CONFIG_DRIVE_STRENGTH: the pin will sink or source at most the current * passed as argument. The argument is in mA. + * @PIN_CONFIG_INPUT_ENABLE: enable the pin's input. Note that this does not + * affect the pin's ability to drive output. 1 enables input, 0 disables + * input. * @PIN_CONFIG_INPUT_SCHMITT_ENABLE: control schmitt-trigger mode on the pin. * If the argument != 0, schmitt-trigger mode is enabled. If it's 0, * schmitt-trigger mode is disabled. @@ -101,6 +104,7 @@ enum pin_config_param { PIN_CONFIG_DRIVE_OPEN_DRAIN, PIN_CONFIG_DRIVE_OPEN_SOURCE, PIN_CONFIG_DRIVE_STRENGTH, + PIN_CONFIG_INPUT_ENABLE, PIN_CONFIG_INPUT_SCHMITT_ENABLE, PIN_CONFIG_INPUT_SCHMITT, PIN_CONFIG_INPUT_DEBOUNCE, -- cgit v1.2.3-59-g8ed1b From 01352fb81658cbf78c55844de8e3d1d606bbf3f8 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Wed, 11 Dec 2013 13:59:08 -0800 Subject: locking: Add an smp_mb__after_unlock_lock() for UNLOCK+BLOCK barrier The Linux kernel has traditionally required that an UNLOCK+LOCK pair act as a full memory barrier when either (1) that UNLOCK+LOCK pair was executed by the same CPU or task, or (2) the same lock variable was used for the UNLOCK and LOCK. It now seems likely that very few places in the kernel rely on this full-memory-barrier semantic, and with the advent of queued locks, providing this semantic either requires complex reasoning, or for some architectures, added overhead. This commit therefore adds a smp_mb__after_unlock_lock(), which may be placed after a LOCK primitive to restore the full-memory-barrier semantic. All definitions are currently no-ops, but will be upgraded for some architectures when queued locks arrive. Signed-off-by: Paul E. McKenney Reviewed-by: Peter Zijlstra Cc: Cc: Linus Torvalds Cc: Andrew Morton Link: http://lkml.kernel.org/r/1386799151-2219-5-git-send-email-paulmck@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- include/linux/spinlock.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'include/linux') diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 75f34949d9ab..3f2867ff0ced 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -130,6 +130,16 @@ do { \ #define smp_mb__before_spinlock() smp_wmb() #endif +/* + * Place this after a lock-acquisition primitive to guarantee that + * an UNLOCK+LOCK pair act as a full barrier. This guarantee applies + * if the UNLOCK and LOCK are executed by the same CPU or if the + * UNLOCK and LOCK operate on the same lock variable. + */ +#ifndef smp_mb__after_unlock_lock +#define smp_mb__after_unlock_lock() do { } while (0) +#endif + /** * raw_spin_unlock_wait - wait until the spinlock gets unlocked * @lock: the spinlock in question. -- cgit v1.2.3-59-g8ed1b From ca13bb3d4e54f5c30089e55d5b8f4bb80c8f05e2 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 5 Nov 2013 15:59:53 +0000 Subject: iommu: add IOMMU_EXEC flag for safely allowing XN mappings Whilst most IOMMU mappings should probably be non-executable, there may be cases (HSA?) where executable mappings are required. This patch introduces a new mapping flag, IOMMU_EXEC, to indicate that the mapping should be mapped as executable. Signed-off-by: Will Deacon --- include/linux/iommu.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/iommu.h b/include/linux/iommu.h index a444c790fa72..709a697c4e02 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -24,9 +24,10 @@ #include #include -#define IOMMU_READ (1) -#define IOMMU_WRITE (2) -#define IOMMU_CACHE (4) /* DMA cache coherency */ +#define IOMMU_READ (1 << 0) +#define IOMMU_WRITE (1 << 1) +#define IOMMU_CACHE (1 << 2) /* DMA cache coherency */ +#define IOMMU_EXEC (1 << 3) struct iommu_ops; struct iommu_group; -- cgit v1.2.3-59-g8ed1b From 320a382746e0ab1304476ea7e986a8d416ab99db Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Wed, 23 Oct 2013 13:07:34 -0600 Subject: NVMe: compat SG_IO ioctl For 32-bit versions of sg3-utils running on a 64-bit system. This is mostly a copy from the relevent portions of fs/compat_ioctl.c, with slight modifications for going through block_device_operations. Signed-off-by: Keith Busch Reviewed-by: Vishal Verma [fixed up CONFIG_COMPAT=n build problems] Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 18 +++++- drivers/block/nvme-scsi.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/nvme.h | 1 + 3 files changed, 165 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index df3daeb6227f..e44350de8a21 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1568,10 +1568,26 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, } } +#ifdef CONFIG_COMPAT +static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode, + unsigned int cmd, unsigned long arg) +{ + struct nvme_ns *ns = bdev->bd_disk->private_data; + + switch (cmd) { + case SG_IO: + return nvme_sg_io32(ns, arg); + } + return nvme_ioctl(bdev, mode, cmd, arg); +} +#else +#define nvme_compat_ioctl NULL +#endif + static const struct block_device_operations nvme_fops = { .owner = THIS_MODULE, .ioctl = nvme_ioctl, - .compat_ioctl = nvme_ioctl, + .compat_ioctl = nvme_compat_ioctl, }; static void nvme_resubmit_bios(struct nvme_queue *nvmeq) diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c index 4a4ff4eb8e23..4a0ceb64e269 100644 --- a/drivers/block/nvme-scsi.c +++ b/drivers/block/nvme-scsi.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -3038,6 +3039,152 @@ int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr) return retcode; } +#ifdef CONFIG_COMPAT +typedef struct sg_io_hdr32 { + compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ + compat_int_t dxfer_direction; /* [i] data transfer direction */ + unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ + unsigned char mx_sb_len; /* [i] max length to write to sbp */ + unsigned short iovec_count; /* [i] 0 implies no scatter gather */ + compat_uint_t dxfer_len; /* [i] byte count of data transfer */ + compat_uint_t dxferp; /* [i], [*io] points to data transfer memory + or scatter gather list */ + compat_uptr_t cmdp; /* [i], [*i] points to command to perform */ + compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */ + compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ + compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */ + compat_int_t pack_id; /* [i->o] unused internally (normally) */ + compat_uptr_t usr_ptr; /* [i->o] unused internally */ + unsigned char status; /* [o] scsi status */ + unsigned char masked_status; /* [o] shifted, masked scsi status */ + unsigned char msg_status; /* [o] messaging level data (optional) */ + unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ + unsigned short host_status; /* [o] errors from host adapter */ + unsigned short driver_status; /* [o] errors from software driver */ + compat_int_t resid; /* [o] dxfer_len - actual_transferred */ + compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */ + compat_uint_t info; /* [o] auxiliary information */ +} sg_io_hdr32_t; /* 64 bytes long (on sparc32) */ + +typedef struct sg_iovec32 { + compat_uint_t iov_base; + compat_uint_t iov_len; +} sg_iovec32_t; + +static int sg_build_iovec(sg_io_hdr_t __user *sgio, void __user *dxferp, u16 iovec_count) +{ + sg_iovec_t __user *iov = (sg_iovec_t __user *) (sgio + 1); + sg_iovec32_t __user *iov32 = dxferp; + int i; + + for (i = 0; i < iovec_count; i++) { + u32 base, len; + + if (get_user(base, &iov32[i].iov_base) || + get_user(len, &iov32[i].iov_len) || + put_user(compat_ptr(base), &iov[i].iov_base) || + put_user(len, &iov[i].iov_len)) + return -EFAULT; + } + + if (put_user(iov, &sgio->dxferp)) + return -EFAULT; + return 0; +} + +int nvme_sg_io32(struct nvme_ns *ns, unsigned long arg) +{ + sg_io_hdr32_t __user *sgio32 = (sg_io_hdr32_t __user *)arg; + sg_io_hdr_t __user *sgio; + u16 iovec_count; + u32 data; + void __user *dxferp; + int err; + int interface_id; + + if (get_user(interface_id, &sgio32->interface_id)) + return -EFAULT; + if (interface_id != 'S') + return -EINVAL; + + if (get_user(iovec_count, &sgio32->iovec_count)) + return -EFAULT; + + { + void __user *top = compat_alloc_user_space(0); + void __user *new = compat_alloc_user_space(sizeof(sg_io_hdr_t) + + (iovec_count * sizeof(sg_iovec_t))); + if (new > top) + return -EINVAL; + + sgio = new; + } + + /* Ok, now construct. */ + if (copy_in_user(&sgio->interface_id, &sgio32->interface_id, + (2 * sizeof(int)) + + (2 * sizeof(unsigned char)) + + (1 * sizeof(unsigned short)) + + (1 * sizeof(unsigned int)))) + return -EFAULT; + + if (get_user(data, &sgio32->dxferp)) + return -EFAULT; + dxferp = compat_ptr(data); + if (iovec_count) { + if (sg_build_iovec(sgio, dxferp, iovec_count)) + return -EFAULT; + } else { + if (put_user(dxferp, &sgio->dxferp)) + return -EFAULT; + } + + { + unsigned char __user *cmdp; + unsigned char __user *sbp; + + if (get_user(data, &sgio32->cmdp)) + return -EFAULT; + cmdp = compat_ptr(data); + + if (get_user(data, &sgio32->sbp)) + return -EFAULT; + sbp = compat_ptr(data); + + if (put_user(cmdp, &sgio->cmdp) || + put_user(sbp, &sgio->sbp)) + return -EFAULT; + } + + if (copy_in_user(&sgio->timeout, &sgio32->timeout, + 3 * sizeof(int))) + return -EFAULT; + + if (get_user(data, &sgio32->usr_ptr)) + return -EFAULT; + if (put_user(compat_ptr(data), &sgio->usr_ptr)) + return -EFAULT; + + err = nvme_sg_io(ns, sgio); + if (err >= 0) { + void __user *datap; + + if (copy_in_user(&sgio32->pack_id, &sgio->pack_id, + sizeof(int)) || + get_user(datap, &sgio->usr_ptr) || + put_user((u32)(unsigned long)datap, + &sgio32->usr_ptr) || + copy_in_user(&sgio32->status, &sgio->status, + (4 * sizeof(unsigned char)) + + (2 * sizeof(unsigned short)) + + (3 * sizeof(int)))) + err = -EFAULT; + } + + return err; +} +#endif + int nvme_sg_get_version_num(int __user *ip) { return put_user(sg_version_num, ip); diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 8119a476cb29..5bc29197d90e 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -165,6 +165,7 @@ int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11, struct sg_io_hdr; int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr); +int nvme_sg_io32(struct nvme_ns *ns, unsigned long arg); int nvme_sg_get_version_num(int __user *ip); #endif /* _LINUX_NVME_H */ -- cgit v1.2.3-59-g8ed1b From d3233433356aa1965b60b08ee61465b20e50474b Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sun, 15 Dec 2013 13:36:51 +0400 Subject: regmap: irq: Allow using zero value for ack_base In some cases, clear interrupt register may be at address 0. This patch allows to use such configurations by adding additional configuration bit to indicate this. [With doc fix from Levente Kurusa -- broonie] Signed-off-by: Alexander Shiyan Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-irq.c | 6 +++--- include/linux/regmap.h | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c index 763c60d3d277..82692068d3cb 100644 --- a/drivers/base/regmap/regmap-irq.c +++ b/drivers/base/regmap/regmap-irq.c @@ -113,7 +113,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data) * OR if there is masked interrupt which hasn't been Acked, * it'll be ignored in irq handler, then may introduce irq storm */ - if (d->mask_buf[i] && d->chip->ack_base) { + if (d->mask_buf[i] && (d->chip->ack_base || d->chip->use_ack)) { reg = d->chip->ack_base + (i * map->reg_stride * d->irq_reg_stride); ret = regmap_write(map, reg, d->mask_buf[i]); @@ -271,7 +271,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d) for (i = 0; i < data->chip->num_regs; i++) { data->status_buf[i] &= ~data->mask_buf[i]; - if (data->status_buf[i] && chip->ack_base) { + if (data->status_buf[i] && (chip->ack_base || chip->use_ack)) { reg = chip->ack_base + (i * map->reg_stride * data->irq_reg_stride); ret = regmap_write(map, reg, data->status_buf[i]); @@ -448,7 +448,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, goto err_alloc; } - if (d->status_buf[i] && chip->ack_base) { + if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) { reg = chip->ack_base + (i * map->reg_stride * d->irq_reg_stride); ret = regmap_write(map, reg, diff --git a/include/linux/regmap.h b/include/linux/regmap.h index e55907804d39..c9e5fb197eb6 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -497,11 +497,13 @@ struct regmap_irq { * * @status_base: Base status register address. * @mask_base: Base mask register address. - * @ack_base: Base ack address. If zero then the chip is clear on read. + * @ack_base: Base ack address. If zero then the chip is clear on read. + * Using zero value is possible with @use_ack bit. * @wake_base: Base address for wake enables. If zero unsupported. * @irq_reg_stride: Stride to use for chips where registers are not contiguous. * @init_ack_masked: Ack all masked interrupts once during initalization. * @mask_invert: Inverted mask register: cleared bits are masked out. + * @use_ack: Use @ack register even if it is zero. * @wake_invert: Inverted wake register: cleared bits are wake enabled. * @runtime_pm: Hold a runtime PM lock on the device when accessing it. * @@ -520,6 +522,7 @@ struct regmap_irq_chip { unsigned int irq_reg_stride; bool init_ack_masked:1; bool mask_invert:1; + bool use_ack:1; bool wake_invert:1; bool runtime_pm:1; -- cgit v1.2.3-59-g8ed1b From 9a6b94584de1a0467d85b435df9c744c5c45a270 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 10 Dec 2013 13:10:36 -0700 Subject: NVMe: Device resume error handling Adds controller error handling on resume power management. If the device fails to initialize, the device is queued for a reset. If the reset fails, a thread is spawned to remove the pci device. If the device resumes as "busy", the device is responding to admin commands but will not create IO queues. In this case, we need to remove the gendisks and free the IO queues since they can't be used and may be holding bios in their lists. From testing, the dma pools require a pci device so this had to change the pci driver 'remove' to release the dma resources in line with that call instead of after all references to the device are released. Signed-off-by: Keith Busch Signed-off-by: Matthew Wilcox --- drivers/block/nvme-core.c | 108 +++++++++++++++++++++++++++++++++++++++------- include/linux/nvme.h | 1 + 2 files changed, 94 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 300766973d76..000bca43c23b 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -58,6 +58,7 @@ module_param(use_threaded_interrupts, int, 0); static DEFINE_SPINLOCK(dev_list_lock); static LIST_HEAD(dev_list); static struct task_struct *nvme_thread; +static struct workqueue_struct *nvme_workq; /* * An NVM Express queue. Each device has at least two (one for admin @@ -1968,7 +1969,6 @@ static int nvme_dev_map(struct nvme_dev *dev) dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) goto disable; - pci_set_drvdata(pdev, dev); dev->bar = ioremap(pci_resource_start(pdev, 0), 8192); if (!dev->bar) goto disable; @@ -1995,9 +1995,9 @@ static void nvme_dev_unmap(struct nvme_dev *dev) if (dev->bar) { iounmap(dev->bar); dev->bar = NULL; + pci_release_regions(dev->pci_dev); } - pci_release_regions(dev->pci_dev); if (pci_is_enabled(dev->pci_dev)) pci_disable_device(dev->pci_dev); } @@ -2085,11 +2085,6 @@ static void nvme_release_instance(struct nvme_dev *dev) static void nvme_free_dev(struct kref *kref) { struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref); - nvme_dev_remove(dev); - nvme_dev_shutdown(dev); - nvme_free_queues(dev); - nvme_release_instance(dev); - nvme_release_prp_pools(dev); kfree(dev->queues); kfree(dev->entry); kfree(dev); @@ -2161,6 +2156,70 @@ static int nvme_dev_start(struct nvme_dev *dev) return result; } +static int nvme_remove_dead_ctrl(void *arg) +{ + struct nvme_dev *dev = (struct nvme_dev *)arg; + struct pci_dev *pdev = dev->pci_dev; + + if (pci_get_drvdata(pdev)) + pci_stop_and_remove_bus_device(pdev); + kref_put(&dev->kref, nvme_free_dev); + return 0; +} + +static void nvme_remove_disks(struct work_struct *ws) +{ + int i; + struct nvme_dev *dev = container_of(ws, struct nvme_dev, reset_work); + + nvme_dev_remove(dev); + spin_lock(&dev_list_lock); + for (i = dev->queue_count - 1; i > 0; i--) { + BUG_ON(!dev->queues[i] || !dev->queues[i]->q_suspended); + nvme_free_queue(dev->queues[i]); + dev->queue_count--; + dev->queues[i] = NULL; + } + spin_unlock(&dev_list_lock); +} + +static int nvme_dev_resume(struct nvme_dev *dev) +{ + int ret; + + ret = nvme_dev_start(dev); + if (ret && ret != -EBUSY) + return ret; + if (ret == -EBUSY) { + spin_lock(&dev_list_lock); + INIT_WORK(&dev->reset_work, nvme_remove_disks); + queue_work(nvme_workq, &dev->reset_work); + spin_unlock(&dev_list_lock); + } + return 0; +} + +static void nvme_dev_reset(struct nvme_dev *dev) +{ + nvme_dev_shutdown(dev); + if (nvme_dev_resume(dev)) { + dev_err(&dev->pci_dev->dev, "Device failed to resume\n"); + kref_get(&dev->kref); + if (IS_ERR(kthread_run(nvme_remove_dead_ctrl, dev, "nvme%d", + dev->instance))) { + dev_err(&dev->pci_dev->dev, + "Failed to start controller remove task\n"); + kref_put(&dev->kref, nvme_free_dev); + } + } +} + +static void nvme_reset_failed_dev(struct work_struct *ws) +{ + struct nvme_dev *dev = container_of(ws, struct nvme_dev, reset_work); + nvme_dev_reset(dev); +} + static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) { int result = -ENOMEM; @@ -2180,7 +2239,7 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) INIT_LIST_HEAD(&dev->namespaces); dev->pci_dev = pdev; - + pci_set_drvdata(pdev, dev); result = nvme_set_instance(dev); if (result) goto free; @@ -2232,7 +2291,19 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) static void nvme_remove(struct pci_dev *pdev) { struct nvme_dev *dev = pci_get_drvdata(pdev); + + spin_lock(&dev_list_lock); + list_del_init(&dev->node); + spin_unlock(&dev_list_lock); + + pci_set_drvdata(pdev, NULL); + flush_work(&dev->reset_work); misc_deregister(&dev->miscdev); + nvme_dev_remove(dev); + nvme_dev_shutdown(dev); + nvme_free_queues(dev); + nvme_release_instance(dev); + nvme_release_prp_pools(dev); kref_put(&dev->kref, nvme_free_dev); } @@ -2256,13 +2327,12 @@ static int nvme_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct nvme_dev *ndev = pci_get_drvdata(pdev); - int ret; - ret = nvme_dev_start(ndev); - /* XXX: should remove gendisks if resume fails */ - if (ret) - nvme_free_queues(ndev); - return ret; + if (nvme_dev_resume(ndev) && !work_busy(&ndev->reset_work)) { + INIT_WORK(&ndev->reset_work, nvme_reset_failed_dev); + queue_work(nvme_workq, &ndev->reset_work); + } + return 0; } static SIMPLE_DEV_PM_OPS(nvme_dev_pm_ops, nvme_suspend, nvme_resume); @@ -2303,9 +2373,14 @@ static int __init nvme_init(void) if (IS_ERR(nvme_thread)) return PTR_ERR(nvme_thread); + result = -ENOMEM; + nvme_workq = create_singlethread_workqueue("nvme"); + if (!nvme_workq) + goto kill_kthread; + result = register_blkdev(nvme_major, "nvme"); if (result < 0) - goto kill_kthread; + goto kill_workq; else if (result > 0) nvme_major = result; @@ -2316,6 +2391,8 @@ static int __init nvme_init(void) unregister_blkdev: unregister_blkdev(nvme_major, "nvme"); + kill_workq: + destroy_workqueue(nvme_workq); kill_kthread: kthread_stop(nvme_thread); return result; @@ -2325,6 +2402,7 @@ static void __exit nvme_exit(void) { pci_unregister_driver(&nvme_driver); unregister_blkdev(nvme_major, "nvme"); + destroy_workqueue(nvme_workq); kthread_stop(nvme_thread); } diff --git a/include/linux/nvme.h b/include/linux/nvme.h index 5bc29197d90e..eed81cc56d7e 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -87,6 +87,7 @@ struct nvme_dev { struct list_head namespaces; struct kref kref; struct miscdevice miscdev; + struct work_struct reset_work; char name[12]; char serial[20]; char model[40]; -- cgit v1.2.3-59-g8ed1b From 9a716579660aa87a4ab4b4d1cac0686fba3707ba Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 13 Dec 2013 17:31:03 +0100 Subject: ARM: tegra: Add Tegra124 powergate support Three new gates have been added for Tegra124: SOR, VIC and IRAM. In addition, PCIe and SATA gates are again supported, like on Tegra20 and Tegra30. Signed-off-by: Thierry Reding Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/powergate.c | 42 +++++++++++++++++++++++++++++++++++++++++ include/linux/tegra-powergate.h | 3 +++ 2 files changed, 45 insertions(+) (limited to 'include/linux') diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index a67c92acb4a6..a8ac634eda77 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -59,6 +59,13 @@ static const u8 tegra114_cpu_domains[] = { TEGRA_POWERGATE_CPU3, }; +static const u8 tegra124_cpu_domains[] = { + TEGRA_POWERGATE_CPU0, + TEGRA_POWERGATE_CPU1, + TEGRA_POWERGATE_CPU2, + TEGRA_POWERGATE_CPU3, +}; + static DEFINE_SPINLOCK(tegra_powergate_lock); static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); @@ -206,6 +213,11 @@ int __init tegra_powergate_init(void) tegra_num_cpu_domains = 4; tegra_cpu_domains = tegra114_cpu_domains; break; + case TEGRA124: + tegra_num_powerdomains = 25; + tegra_num_cpu_domains = 4; + tegra_cpu_domains = tegra124_cpu_domains; + break; default: /* Unknown Tegra variant. Disable powergating */ tegra_num_powerdomains = 0; @@ -267,6 +279,33 @@ static const char * const powergate_name_t114[] = { [TEGRA_POWERGATE_XUSBC] = "xusbc", }; +static const char * const powergate_name_t124[] = { + [TEGRA_POWERGATE_CPU] = "crail", + [TEGRA_POWERGATE_3D] = "3d", + [TEGRA_POWERGATE_VENC] = "venc", + [TEGRA_POWERGATE_PCIE] = "pcie", + [TEGRA_POWERGATE_VDEC] = "vdec", + [TEGRA_POWERGATE_L2] = "l2", + [TEGRA_POWERGATE_MPE] = "mpe", + [TEGRA_POWERGATE_HEG] = "heg", + [TEGRA_POWERGATE_SATA] = "sata", + [TEGRA_POWERGATE_CPU1] = "cpu1", + [TEGRA_POWERGATE_CPU2] = "cpu2", + [TEGRA_POWERGATE_CPU3] = "cpu3", + [TEGRA_POWERGATE_CELP] = "celp", + [TEGRA_POWERGATE_CPU0] = "cpu0", + [TEGRA_POWERGATE_C0NC] = "c0nc", + [TEGRA_POWERGATE_C1NC] = "c1nc", + [TEGRA_POWERGATE_SOR] = "sor", + [TEGRA_POWERGATE_DIS] = "dis", + [TEGRA_POWERGATE_DISB] = "disb", + [TEGRA_POWERGATE_XUSBA] = "xusba", + [TEGRA_POWERGATE_XUSBB] = "xusbb", + [TEGRA_POWERGATE_XUSBC] = "xusbc", + [TEGRA_POWERGATE_VIC] = "vic", + [TEGRA_POWERGATE_IRAM] = "iram", +}; + static int powergate_show(struct seq_file *s, void *data) { int i; @@ -311,6 +350,9 @@ int __init tegra_powergate_debugfs_init(void) case TEGRA114: powergate_name = powergate_name_t114; break; + case TEGRA124: + powergate_name = powergate_name_t124; + break; } if (powergate_name) { diff --git a/include/linux/tegra-powergate.h b/include/linux/tegra-powergate.h index afe442d2629a..bccad3cfff87 100644 --- a/include/linux/tegra-powergate.h +++ b/include/linux/tegra-powergate.h @@ -38,11 +38,14 @@ struct reset_control; #define TEGRA_POWERGATE_CPU0 14 #define TEGRA_POWERGATE_C0NC 15 #define TEGRA_POWERGATE_C1NC 16 +#define TEGRA_POWERGATE_SOR 17 #define TEGRA_POWERGATE_DIS 18 #define TEGRA_POWERGATE_DISB 19 #define TEGRA_POWERGATE_XUSBA 20 #define TEGRA_POWERGATE_XUSBB 21 #define TEGRA_POWERGATE_XUSBC 22 +#define TEGRA_POWERGATE_VIC 23 +#define TEGRA_POWERGATE_IRAM 24 #define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D -- cgit v1.2.3-59-g8ed1b From 9d4450ae87398e248e8700e3507748e0d1751e25 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 16 Dec 2013 21:42:28 +0100 Subject: ARM: tegra: Add IO rail support Add tegra_io_rail_power_off() and tegra_io_rail_power_on() functions to put IO rails into or out of deep powerdown mode, respectively. Signed-off-by: Thierry Reding Signed-off-by: Stephen Warren --- arch/arm/mach-tegra/powergate.c | 132 ++++++++++++++++++++++++++++++++++++++++ include/linux/tegra-powergate.h | 45 ++++++++++++++ 2 files changed, 177 insertions(+) (limited to 'include/linux') diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index 0026fb6c984b..3d0c537d9b94 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -34,6 +34,10 @@ #include "fuse.h" #include "iomap.h" +#define DPD_SAMPLE 0x020 +#define DPD_SAMPLE_ENABLE (1 << 0) +#define DPD_SAMPLE_DISABLE (0 << 0) + #define PWRGATE_TOGGLE 0x30 #define PWRGATE_TOGGLE_START (1 << 8) @@ -41,6 +45,17 @@ #define PWRGATE_STATUS 0x38 +#define IO_DPD_REQ 0x1b8 +#define IO_DPD_REQ_CODE_IDLE (0 << 30) +#define IO_DPD_REQ_CODE_OFF (1 << 30) +#define IO_DPD_REQ_CODE_ON (2 << 30) +#define IO_DPD_REQ_CODE_MASK (3 << 30) + +#define IO_DPD_STATUS 0x1bc +#define IO_DPD2_REQ 0x1c0 +#define IO_DPD2_STATUS 0x1c4 +#define SEL_DPD_TIM 0x1c8 + #define GPU_RG_CNTRL 0x2d4 static int tegra_num_powerdomains; @@ -379,3 +394,120 @@ int __init tegra_powergate_debugfs_init(void) } #endif + +static int tegra_io_rail_prepare(int id, unsigned long *request, + unsigned long *status, unsigned int *bit) +{ + unsigned long rate, value; + struct clk *clk; + + *bit = id % 32; + + /* + * There are two sets of 30 bits to select IO rails, but bits 30 and + * 31 are control bits rather than IO rail selection bits. + */ + if (id > 63 || *bit == 30 || *bit == 31) + return -EINVAL; + + if (id < 32) { + *status = IO_DPD_STATUS; + *request = IO_DPD_REQ; + } else { + *status = IO_DPD2_STATUS; + *request = IO_DPD2_REQ; + } + + clk = clk_get_sys(NULL, "pclk"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + rate = clk_get_rate(clk); + clk_put(clk); + + pmc_write(DPD_SAMPLE_ENABLE, DPD_SAMPLE); + + /* must be at least 200 ns, in APB (PCLK) clock cycles */ + value = DIV_ROUND_UP(1000000000, rate); + value = DIV_ROUND_UP(200, value); + pmc_write(value, SEL_DPD_TIM); + + return 0; +} + +static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, + unsigned long val, unsigned long timeout) +{ + unsigned long value; + + timeout = jiffies + msecs_to_jiffies(timeout); + + while (time_after(timeout, jiffies)) { + value = pmc_read(offset); + if ((value & mask) == val) + return 0; + + usleep_range(250, 1000); + } + + return -ETIMEDOUT; +} + +static void tegra_io_rail_unprepare(void) +{ + pmc_write(DPD_SAMPLE_DISABLE, DPD_SAMPLE); +} + +int tegra_io_rail_power_on(int id) +{ + unsigned long request, status, value; + unsigned int bit, mask; + int err; + + err = tegra_io_rail_prepare(id, &request, &status, &bit); + if (err < 0) + return err; + + mask = 1 << bit; + + value = pmc_read(request); + value |= mask; + value &= ~IO_DPD_REQ_CODE_MASK; + value |= IO_DPD_REQ_CODE_OFF; + pmc_write(value, request); + + err = tegra_io_rail_poll(status, mask, 0, 250); + if (err < 0) + return err; + + tegra_io_rail_unprepare(); + + return 0; +} + +int tegra_io_rail_power_off(int id) +{ + unsigned long request, status, value; + unsigned int bit, mask; + int err; + + err = tegra_io_rail_prepare(id, &request, &status, &bit); + if (err < 0) + return err; + + mask = 1 << bit; + + value = pmc_read(request); + value |= mask; + value &= ~IO_DPD_REQ_CODE_MASK; + value |= IO_DPD_REQ_CODE_ON; + pmc_write(value, request); + + err = tegra_io_rail_poll(status, mask, mask, 250); + if (err < 0) + return err; + + tegra_io_rail_unprepare(); + + return 0; +} diff --git a/include/linux/tegra-powergate.h b/include/linux/tegra-powergate.h index bccad3cfff87..e6f2ab3014a7 100644 --- a/include/linux/tegra-powergate.h +++ b/include/linux/tegra-powergate.h @@ -49,6 +49,38 @@ struct reset_control; #define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D +#define TEGRA_IO_RAIL_CSIA 0 +#define TEGRA_IO_RAIL_CSIB 1 +#define TEGRA_IO_RAIL_DSI 2 +#define TEGRA_IO_RAIL_MIPI_BIAS 3 +#define TEGRA_IO_RAIL_PEX_BIAS 4 +#define TEGRA_IO_RAIL_PEX_CLK1 5 +#define TEGRA_IO_RAIL_PEX_CLK2 6 +#define TEGRA_IO_RAIL_USB0 9 +#define TEGRA_IO_RAIL_USB1 10 +#define TEGRA_IO_RAIL_USB2 11 +#define TEGRA_IO_RAIL_USB_BIAS 12 +#define TEGRA_IO_RAIL_NAND 13 +#define TEGRA_IO_RAIL_UART 14 +#define TEGRA_IO_RAIL_BB 15 +#define TEGRA_IO_RAIL_AUDIO 17 +#define TEGRA_IO_RAIL_HSIC 19 +#define TEGRA_IO_RAIL_COMP 22 +#define TEGRA_IO_RAIL_HDMI 28 +#define TEGRA_IO_RAIL_PEX_CNTRL 32 +#define TEGRA_IO_RAIL_SDMMC1 33 +#define TEGRA_IO_RAIL_SDMMC3 34 +#define TEGRA_IO_RAIL_SDMMC4 35 +#define TEGRA_IO_RAIL_CAM 36 +#define TEGRA_IO_RAIL_RES 37 +#define TEGRA_IO_RAIL_HV 38 +#define TEGRA_IO_RAIL_DSIB 39 +#define TEGRA_IO_RAIL_DSIC 40 +#define TEGRA_IO_RAIL_DSID 41 +#define TEGRA_IO_RAIL_CSIE 44 +#define TEGRA_IO_RAIL_LVDS 57 +#define TEGRA_IO_RAIL_SYS_DDC 58 + #ifdef CONFIG_ARCH_TEGRA int tegra_powergate_is_powered(int id); int tegra_powergate_power_on(int id); @@ -58,6 +90,9 @@ int tegra_powergate_remove_clamping(int id); /* Must be called with clk disabled, and returns with clk enabled */ int tegra_powergate_sequence_power_up(int id, struct clk *clk, struct reset_control *rst); + +int tegra_io_rail_power_on(int id); +int tegra_io_rail_power_off(int id); #else static inline int tegra_powergate_is_powered(int id) { @@ -84,6 +119,16 @@ static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk, { return -ENOSYS; } + +static inline int tegra_io_rail_power_on(int id) +{ + return -ENOSYS; +} + +static inline int tegra_io_rail_power_off(int id) +{ + return -ENOSYS; +} #endif #endif /* _MACH_TEGRA_POWERGATE_H_ */ -- cgit v1.2.3-59-g8ed1b From 89c1f60746106755e29dcc3db9f22e37000891ef Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 13 Dec 2013 18:27:44 -0800 Subject: spi: Order fields in spi_device for better packing Now that spi_device->mode is a u16, the chip_select, bits_per_mode, and mode fields pack poorly, taking 8 bytes: four data and four padding. By moving (u8)bits_per_word up one position, to after (u8)chip_select, they pack better and only use 4 bytes. Signed-off-by: Trent Piepho Reviewed-by: Sourav Poddar Tested-by: Sourav Poddar g Signed-off-by: Mark Brown --- include/linux/spi/spi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 8c62ba74dd91..27a882978c15 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -75,6 +75,7 @@ struct spi_device { struct spi_master *master; u32 max_speed_hz; u8 chip_select; + u8 bits_per_word; u16 mode; #define SPI_CPHA 0x01 /* clock phase */ #define SPI_CPOL 0x02 /* clock polarity */ @@ -92,7 +93,6 @@ struct spi_device { #define SPI_TX_QUAD 0x200 /* transmit with 4 wires */ #define SPI_RX_DUAL 0x400 /* receive with 2 wires */ #define SPI_RX_QUAD 0x800 /* receive with 4 wires */ - u8 bits_per_word; int irq; void *controller_state; void *controller_data; -- cgit v1.2.3-59-g8ed1b From 1bd53a7efdc988163ec4c25f656df38dbe500632 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Thu, 12 Dec 2013 15:23:23 +0800 Subject: sched/numa: Drop sysctl_numa_balancing_settle_count sysctl commit 887c290e (sched/numa: Decide whether to favour task or group weights based on swap candidate relationships) drop the check against sysctl_numa_balancing_settle_count, this patch remove the sysctl. Signed-off-by: Wanpeng Li Acked-by: Mel Gorman Reviewed-by: Rik van Riel Acked-by: David Rientjes Signed-off-by: Peter Zijlstra Cc: Andrew Morton Cc: Naoya Horiguchi Link: http://lkml.kernel.org/r/1386833006-6600-1-git-send-email-liwanp@linux.vnet.ibm.com Signed-off-by: Ingo Molnar --- Documentation/sysctl/kernel.txt | 5 ----- include/linux/sched/sysctl.h | 1 - kernel/sched/fair.c | 9 --------- kernel/sysctl.c | 7 ------- 4 files changed, 22 deletions(-) (limited to 'include/linux') diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt index 26b7ee491df8..6d486404200e 100644 --- a/Documentation/sysctl/kernel.txt +++ b/Documentation/sysctl/kernel.txt @@ -428,11 +428,6 @@ rate for each task. numa_balancing_scan_size_mb is how many megabytes worth of pages are scanned for a given scan. -numa_balancing_settle_count is how many scan periods must complete before -the schedule balancer stops pushing the task towards a preferred node. This -gives the scheduler a chance to place the task on an alternative node if the -preferred node is overloaded. - numa_balancing_migrate_deferred is how many page migrations get skipped unconditionally, after a page migration is skipped because a page is shared with other tasks. This reduces page migration overhead, and determines diff --git a/include/linux/sched/sysctl.h b/include/linux/sched/sysctl.h index 41467f8ff8ec..31e0193cb0c5 100644 --- a/include/linux/sched/sysctl.h +++ b/include/linux/sched/sysctl.h @@ -48,7 +48,6 @@ extern unsigned int sysctl_numa_balancing_scan_delay; extern unsigned int sysctl_numa_balancing_scan_period_min; extern unsigned int sysctl_numa_balancing_scan_period_max; extern unsigned int sysctl_numa_balancing_scan_size; -extern unsigned int sysctl_numa_balancing_settle_count; #ifdef CONFIG_SCHED_DEBUG extern unsigned int sysctl_sched_migration_cost; diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index a9185f7c9446..fcb6c17f7d79 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -872,15 +872,6 @@ static unsigned int task_scan_max(struct task_struct *p) return max(smin, smax); } -/* - * Once a preferred node is selected the scheduler balancer will prefer moving - * a task to that node for sysctl_numa_balancing_settle_count number of PTE - * scans. This will give the process the chance to accumulate more faults on - * the preferred node but still allow the scheduler to move the task again if - * the nodes CPUs are overloaded. - */ -unsigned int sysctl_numa_balancing_settle_count __read_mostly = 4; - static void account_numa_enqueue(struct rq *rq, struct task_struct *p) { rq->nr_numa_running += (p->numa_preferred_nid != -1); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 34a604726d0b..c8da99f905cf 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -384,13 +384,6 @@ static struct ctl_table kern_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, - { - .procname = "numa_balancing_settle_count", - .data = &sysctl_numa_balancing_settle_count, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, { .procname = "numa_balancing_migrate_deferred", .data = &sysctl_numa_balancing_migrate_deferred, -- cgit v1.2.3-59-g8ed1b From bb8b9d095c5c56cce99576cfef0cf9b989f7120d Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 16:02:55 -0500 Subject: kernfs: add @mode to kernfs_create_dir[_ns]() sysfs assumed 0755 for all newly created directories and kernfs inherited it. This assumption is unnecessarily restrictive and inconsistent with kernfs_create_file[_ns](). This patch adds @mode parameter to kernfs_create_dir[_ns]() and update uses in sysfs accordingly. Among others, this will be useful for implementations of the planned ->mkdir() method. This patch doesn't introduce any behavior differences. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 9 +++++---- fs/sysfs/dir.c | 3 ++- fs/sysfs/group.c | 3 ++- include/linux/kernfs.h | 13 +++++++------ 4 files changed, 16 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 6520066c49ea..e55bb02f15a4 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -639,22 +639,23 @@ void kernfs_destroy_root(struct kernfs_root *root) * kernfs_create_dir_ns - create a directory * @parent: parent in which to create a new directory * @name: name of the new directory + * @mode: mode of the new directory * @priv: opaque data associated with the new directory * @ns: optional namespace tag of the directory * * Returns the created node on success, ERR_PTR() value on failure. */ struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, - const char *name, void *priv, - const void *ns) + const char *name, umode_t mode, + void *priv, const void *ns) { - umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; struct kernfs_addrm_cxt acxt; struct kernfs_node *kn; int rc; /* allocate */ - kn = kernfs_new_node(kernfs_root(parent), name, mode, KERNFS_DIR); + kn = kernfs_new_node(kernfs_root(parent), name, mode | S_IFDIR, + KERNFS_DIR); if (!kn) return ERR_PTR(-ENOMEM); diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index aa007401bfc9..ee0d761c3179 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -73,7 +73,8 @@ int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) if (!parent) return -ENOENT; - kn = kernfs_create_dir_ns(parent, kobject_name(kobj), kobj, ns); + kn = kernfs_create_dir_ns(parent, kobject_name(kobj), + S_IRWXU | S_IRUGO | S_IXUGO, kobj, ns); if (IS_ERR(kn)) { if (PTR_ERR(kn) == -EEXIST) sysfs_warn_dup(parent, kobject_name(kobj)); diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c index 4d00d3996477..6b579387c67a 100644 --- a/fs/sysfs/group.c +++ b/fs/sysfs/group.c @@ -100,7 +100,8 @@ static int internal_create_group(struct kobject *kobj, int update, return -EINVAL; } if (grp->name) { - kn = kernfs_create_dir(kobj->sd, grp->name, kobj); + kn = kernfs_create_dir(kobj->sd, grp->name, + S_IRWXU | S_IRUGO | S_IXUGO, kobj); if (IS_ERR(kn)) { if (PTR_ERR(kn) == -EEXIST) sysfs_warn_dup(kobj->sd, grp->name); diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index e9c4e3a03960..0ca2aedfd31b 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -210,8 +210,8 @@ struct kernfs_root *kernfs_create_root(void *priv); void kernfs_destroy_root(struct kernfs_root *root); struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, - const char *name, void *priv, - const void *ns); + const char *name, umode_t mode, + void *priv, const void *ns); struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, const char *name, umode_t mode, loff_t size, @@ -260,8 +260,8 @@ static inline struct kernfs_root *kernfs_create_root(void *priv) static inline void kernfs_destroy_root(struct kernfs_root *root) { } static inline struct kernfs_node * -kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, void *priv, - const void *ns) +kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, + umode_t mode, void *priv, const void *ns) { return ERR_PTR(-ENOSYS); } static inline struct kernfs_node * @@ -314,9 +314,10 @@ kernfs_find_and_get(struct kernfs_node *kn, const char *name) } static inline struct kernfs_node * -kernfs_create_dir(struct kernfs_node *parent, const char *name, void *priv) +kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode, + void *priv) { - return kernfs_create_dir_ns(parent, name, priv, NULL); + return kernfs_create_dir_ns(parent, name, mode, priv, NULL); } static inline struct kernfs_node * -- cgit v1.2.3-59-g8ed1b From 2063d608f5110d120db60e896ec2c70c95bb7978 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 16:02:57 -0500 Subject: kernfs: mark static names with KERNFS_STATIC_NAME Because sysfs used struct attribute which are supposed to stay constant, sysfs didn't copy names when creating regular files. The specified string for name was supposed to stay constant. Such distinction isn't inherent for kernfs. kernfs_create_file[_ns]() should be able to take the same @name as kernfs_create_dir[_ns]() As there can be huge number of sysfs attributes, we still want to be able to use static names for sysfs attributes. This patch renames kernfs_create_file_ns_key() to __kernfs_create_file() and adds @name_is_static parameter so that the caller can explicitly indicate that @name can be used without copying. kernfs is updated to use KERNFS_STATIC_NAME to distinguish static and copied names. This patch doesn't introduce any behavior changes. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 8 ++++---- fs/kernfs/file.c | 23 +++++++++++++++-------- fs/kernfs/kernfs-internal.h | 2 +- fs/sysfs/file.c | 4 ++-- include/linux/kernfs.h | 27 ++++++++++++++------------- 5 files changed, 36 insertions(+), 28 deletions(-) (limited to 'include/linux') diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index ba5f372a226d..e1681775abd5 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -240,7 +240,7 @@ void kernfs_put(struct kernfs_node *kn) if (kernfs_type(kn) == KERNFS_LINK) kernfs_put(kn->symlink.target_kn); - if (kernfs_type(kn) & KERNFS_COPY_NAME) + if (!(kn->flags & KERNFS_STATIC_NAME)) kfree(kn->name); if (kn->iattr) { if (kn->iattr->ia_secdata) @@ -336,13 +336,13 @@ const struct dentry_operations kernfs_dops = { }; struct kernfs_node *kernfs_new_node(struct kernfs_root *root, const char *name, - umode_t mode, int type) + umode_t mode, unsigned flags) { char *dup_name = NULL; struct kernfs_node *kn; int ret; - if (type & KERNFS_COPY_NAME) { + if (!(flags & KERNFS_STATIC_NAME)) { name = dup_name = kstrdup(name, GFP_KERNEL); if (!name) return NULL; @@ -362,7 +362,7 @@ struct kernfs_node *kernfs_new_node(struct kernfs_root *root, const char *name, kn->name = name; kn->mode = mode; - kn->flags = type | KERNFS_REMOVED; + kn->flags = flags | KERNFS_REMOVED; return kn; diff --git a/fs/kernfs/file.c b/fs/kernfs/file.c index 053cfd9a6a40..316604cc3a1c 100644 --- a/fs/kernfs/file.c +++ b/fs/kernfs/file.c @@ -762,7 +762,7 @@ const struct file_operations kernfs_file_fops = { }; /** - * kernfs_create_file_ns_key - create a file + * __kernfs_create_file - kernfs internal function to create a file * @parent: directory to create the file in * @name: name of the file * @mode: mode of the file @@ -770,23 +770,30 @@ const struct file_operations kernfs_file_fops = { * @ops: kernfs operations for the file * @priv: private data for the file * @ns: optional namespace tag of the file + * @static_name: don't copy file name * @key: lockdep key for the file's active_ref, %NULL to disable lockdep * * Returns the created node on success, ERR_PTR() value on error. */ -struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, - const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, - void *priv, const void *ns, - struct lock_class_key *key) +struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns, + bool name_is_static, + struct lock_class_key *key) { struct kernfs_addrm_cxt acxt; struct kernfs_node *kn; + unsigned flags; int rc; + flags = KERNFS_FILE; + if (name_is_static) + flags |= KERNFS_STATIC_NAME; + kn = kernfs_new_node(kernfs_root(parent), name, - (mode & S_IALLUGO) | S_IFREG, KERNFS_FILE); + (mode & S_IALLUGO) | S_IFREG, flags); if (!kn) return ERR_PTR(-ENOMEM); diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h index a4ff491fd59c..c6ba5bc37a98 100644 --- a/fs/kernfs/kernfs-internal.h +++ b/fs/kernfs/kernfs-internal.h @@ -105,7 +105,7 @@ int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn, struct kernfs_node *parent); void kernfs_addrm_finish(struct kernfs_addrm_cxt *acxt); struct kernfs_node *kernfs_new_node(struct kernfs_root *root, const char *name, - umode_t mode, int type); + umode_t mode, unsigned flags); /* * file.c diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index fe6388fbd154..810cf6e613e5 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -252,8 +252,8 @@ int sysfs_add_file_mode_ns(struct kernfs_node *parent, if (!attr->ignore_lockdep) key = attr->key ?: (struct lock_class_key *)&attr->skey; #endif - kn = kernfs_create_file_ns_key(parent, attr->name, mode, size, - ops, (void *)attr, ns, key); + kn = __kernfs_create_file(parent, attr->name, mode, size, ops, + (void *)attr, ns, true, key); if (IS_ERR(kn)) { if (PTR_ERR(kn) == -EEXIST) sysfs_warn_dup(parent, attr->name); diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 0ca2aedfd31b..321ed84ad4ce 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -34,7 +34,6 @@ enum kernfs_node_type { }; #define KERNFS_TYPE_MASK 0x000f -#define KERNFS_COPY_NAME (KERNFS_DIR | KERNFS_LINK) #define KERNFS_ACTIVE_REF KERNFS_FILE #define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK @@ -44,6 +43,7 @@ enum kernfs_node_flag { KERNFS_HAS_SEQ_SHOW = 0x0040, KERNFS_HAS_MMAP = 0x0080, KERNFS_LOCKDEP = 0x0100, + KERNFS_STATIC_NAME = 0x0200, }; /* type-specific structures for kernfs_node union members */ @@ -212,12 +212,13 @@ void kernfs_destroy_root(struct kernfs_root *root); struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, umode_t mode, void *priv, const void *ns); -struct kernfs_node *kernfs_create_file_ns_key(struct kernfs_node *parent, - const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, - void *priv, const void *ns, - struct lock_class_key *key); +struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, + const char *name, + umode_t mode, loff_t size, + const struct kernfs_ops *ops, + void *priv, const void *ns, + bool name_is_static, + struct lock_class_key *key); struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, const char *name, struct kernfs_node *target); @@ -265,10 +266,10 @@ kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, { return ERR_PTR(-ENOSYS); } static inline struct kernfs_node * -kernfs_create_file_ns_key(struct kernfs_node *parent, const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, void *priv, - const void *ns, struct lock_class_key *key) +__kernfs_create_file(struct kernfs_node *parent, const char *name, + umode_t mode, loff_t size, const struct kernfs_ops *ops, + void *priv, const void *ns, bool name_is_static, + struct lock_class_key *key) { return ERR_PTR(-ENOSYS); } static inline struct kernfs_node * @@ -330,8 +331,8 @@ kernfs_create_file_ns(struct kernfs_node *parent, const char *name, #ifdef CONFIG_DEBUG_LOCK_ALLOC key = (struct lock_class_key *)&ops->lockdep_key; #endif - return kernfs_create_file_ns_key(parent, name, mode, size, ops, priv, - ns, key); + return __kernfs_create_file(parent, name, mode, size, ops, priv, ns, + false, key); } static inline struct kernfs_node * -- cgit v1.2.3-59-g8ed1b From 80b9bbefc345079bddc4959de016ba4074b0c8d6 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 11 Dec 2013 16:03:00 -0500 Subject: kernfs: add kernfs_dir_ops Add support for mkdir(2), rmdir(2) and rename(2) syscalls. This is implemented through optional kernfs_dir_ops callback table which can be specified on kernfs_create_root(). An implemented callback is invoked when the matching syscall is invoked. As kernfs keep dcache syncs with internal representation and revalidates dentries on each access, the implementation of these methods is extremely simple. Each just discovers the relevant kernfs_node(s) and invokes the requested callback which is allowed to do any kernfs operations and the end result doesn't necessarily have to match the expected semantics of the syscall. This will be used to convert cgroup to use kernfs instead of its own filesystem implementation. Signed-off-by: Tejun Heo Signed-off-by: Greg Kroah-Hartman --- fs/kernfs/dir.c | 44 +++++++++++++++++++++++++++++++++++++++++++- fs/sysfs/mount.c | 2 +- include/linux/kernfs.h | 21 +++++++++++++++++++-- 3 files changed, 63 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 42c5b9f23b41..510b5062ef30 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -583,12 +583,13 @@ EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); /** * kernfs_create_root - create a new kernfs hierarchy + * @kdops: optional directory syscall operations for the hierarchy * @priv: opaque data associated with the new directory * * Returns the root of the new hierarchy on success, ERR_PTR() value on * failure. */ -struct kernfs_root *kernfs_create_root(void *priv) +struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv) { struct kernfs_root *root; struct kernfs_node *kn; @@ -610,6 +611,7 @@ struct kernfs_root *kernfs_create_root(void *priv) kn->priv = priv; kn->dir.root = root; + root->dir_ops = kdops; root->kn = kn; return root; @@ -706,6 +708,42 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir, return ret; } +static int kernfs_iop_mkdir(struct inode *dir, struct dentry *dentry, + umode_t mode) +{ + struct kernfs_node *parent = dir->i_private; + struct kernfs_dir_ops *kdops = kernfs_root(parent)->dir_ops; + + if (!kdops || !kdops->mkdir) + return -EPERM; + + return kdops->mkdir(parent, dentry->d_name.name, mode); +} + +static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry) +{ + struct kernfs_node *kn = dentry->d_fsdata; + struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops; + + if (!kdops || !kdops->rmdir) + return -EPERM; + + return kdops->rmdir(kn); +} + +static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) +{ + struct kernfs_node *kn = old_dentry->d_fsdata; + struct kernfs_node *new_parent = new_dir->i_private; + struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops; + + if (!kdops || !kdops->rename) + return -EPERM; + + return kdops->rename(kn, new_parent, new_dentry->d_name.name); +} + const struct inode_operations kernfs_dir_iops = { .lookup = kernfs_iop_lookup, .permission = kernfs_iop_permission, @@ -715,6 +753,10 @@ const struct inode_operations kernfs_dir_iops = { .removexattr = kernfs_iop_removexattr, .getxattr = kernfs_iop_getxattr, .listxattr = kernfs_iop_listxattr, + + .mkdir = kernfs_iop_mkdir, + .rmdir = kernfs_iop_rmdir, + .rename = kernfs_iop_rename, }; static struct kernfs_node *kernfs_leftmost_descendant(struct kernfs_node *pos) diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 701a56f341c6..6211230814fd 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -62,7 +62,7 @@ int __init sysfs_init(void) { int err; - sysfs_root = kernfs_create_root(NULL); + sysfs_root = kernfs_create_root(NULL, NULL); if (IS_ERR(sysfs_root)) return PTR_ERR(sysfs_root); diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 321ed84ad4ce..d2c439db4efa 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -111,12 +111,27 @@ struct kernfs_node { struct kernfs_iattrs *iattr; }; +/* + * kernfs_dir_ops may be specified on kernfs_create_root() to support + * directory manipulation syscalls. These optional callbacks are invoked + * on the matching syscalls and can perform any kernfs operations which + * don't necessarily have to be the exact operation requested. + */ +struct kernfs_dir_ops { + int (*mkdir)(struct kernfs_node *parent, const char *name, + umode_t mode); + int (*rmdir)(struct kernfs_node *kn); + int (*rename)(struct kernfs_node *kn, struct kernfs_node *new_parent, + const char *new_name); +}; + struct kernfs_root { /* published fields */ struct kernfs_node *kn; /* private fields, do not use outside kernfs proper */ struct ida ino_ida; + struct kernfs_dir_ops *dir_ops; }; struct kernfs_open_file { @@ -206,7 +221,8 @@ struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, void kernfs_get(struct kernfs_node *kn); void kernfs_put(struct kernfs_node *kn); -struct kernfs_root *kernfs_create_root(void *priv); +struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, + void *priv); void kernfs_destroy_root(struct kernfs_root *root); struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, @@ -255,7 +271,8 @@ kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name, static inline void kernfs_get(struct kernfs_node *kn) { } static inline void kernfs_put(struct kernfs_node *kn) { } -static inline struct kernfs_root *kernfs_create_root(void *priv) +static inline struct kernfs_root * +kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv) { return ERR_PTR(-ENOSYS); } static inline void kernfs_destroy_root(struct kernfs_root *root) { } -- cgit v1.2.3-59-g8ed1b From 8f898bfd048f65856d8911a89b1616ad3e677c6c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 17 Dec 2013 09:33:18 -0800 Subject: Revert "serial: pl011: use DMA RX polling by default" This reverts commit 17438217a6f5e33d920ed3821a4b857311cc2872 on request of Linus Walleij: Greg can you please drop or revert commit 17438217a6f5e33d920ed3821a4b857311cc2872 "serial: pl011: use DMA RX polling by default" from the TTY tree until this has been sorted out? Cc: Linus Walleij Cc: Guennadi Liakhovetski Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 2 +- include/linux/amba/serial.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index c8cc8f02b092..a183aceb6d15 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -325,7 +325,7 @@ static void pl011_dma_probe_initcall(struct device *dev, struct uart_amba_port * dmaengine_slave_config(chan, &rx_conf); uap->dmarx.chan = chan; - if (plat) { + if (plat && plat->dma_rx_poll_enable) { /* Set poll rate if specified. */ if (plat->dma_rx_poll_rate) { uap->dmarx.auto_poll_rate = false; diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h index 0891ea0458f6..0ddb5c02ad8b 100644 --- a/include/linux/amba/serial.h +++ b/include/linux/amba/serial.h @@ -203,6 +203,7 @@ struct amba_pl011_data { bool (*dma_filter)(struct dma_chan *chan, void *filter_param); void *dma_rx_param; void *dma_tx_param; + bool dma_rx_poll_enable; unsigned int dma_rx_poll_rate; unsigned int dma_rx_poll_timeout; void (*init) (void); -- cgit v1.2.3-59-g8ed1b From e117e742d310683b410951faeab4b13b6c3c609f Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 13 Dec 2013 12:23:38 +0100 Subject: usb: gadget: add "maxpacket_limit" field to struct usb_ep This patch adds "maxpacket_limit" to struct usb_ep. This field contains maximum value of maxpacket supported by driver, and is set in driver probe. This value should be used by autoconfig() function, because value of field "maxpacket" is set to value from endpoint descriptor when endpoint becomes enabled. So when autoconfig() function will be called again for this endpoint, "maxpacket" value will contain wMaxPacketSize from descriptior instead of maximum packet size for this endpoint. For this reason this patch adds new field "maxpacket_limit" which contains value of maximum packet size (which defines maximum endpoint capabilities). This value is used in ep_matches() function used by autoconfig(). Value of "maxpacket_limit" should be set in UDC driver probe function, using usb_ep_set_maxpacket_limit() function, defined in gadget.h. This function set choosen value to both "maxpacket_limit" and "maxpacket" fields. This patch modifies UDC drivers by adding support for maxpacket_limit. Signed-off-by: Robert Baldyga Signed-off-by: Kyungmin Park Signed-off-by: Felipe Balbi --- drivers/usb/chipidea/udc.c | 4 ++-- drivers/usb/dwc3/gadget.c | 4 ++-- drivers/usb/gadget/amd5536udc.c | 15 +++++++++------ drivers/usb/gadget/at91_udc.c | 16 ++++++++-------- drivers/usb/gadget/atmel_usba_udc.c | 5 +++-- drivers/usb/gadget/bcm63xx_udc.c | 4 ++-- drivers/usb/gadget/dummy_hcd.c | 2 +- drivers/usb/gadget/epautoconf.c | 6 +++--- drivers/usb/gadget/fotg210-udc.c | 3 ++- drivers/usb/gadget/fsl_qe_udc.c | 2 +- drivers/usb/gadget/fsl_udc_core.c | 5 +++-- drivers/usb/gadget/fusb300_udc.c | 4 ++-- drivers/usb/gadget/goku_udc.c | 4 ++-- drivers/usb/gadget/lpc32xx_udc.c | 2 +- drivers/usb/gadget/m66592-udc.c | 4 ++-- drivers/usb/gadget/mv_u3d_core.c | 4 ++-- drivers/usb/gadget/mv_udc_core.c | 4 ++-- drivers/usb/gadget/net2272.c | 4 ++-- drivers/usb/gadget/net2280.c | 8 ++++---- drivers/usb/gadget/omap_udc.c | 3 ++- drivers/usb/gadget/pch_udc.c | 6 +++--- drivers/usb/gadget/pxa25x_udc.c | 1 + drivers/usb/gadget/pxa27x_udc.c | 5 ++++- drivers/usb/gadget/r8a66597-udc.c | 4 ++-- drivers/usb/gadget/s3c-hsotg.c | 2 +- drivers/usb/gadget/s3c-hsudc.c | 2 +- drivers/usb/gadget/s3c2410_udc.c | 1 + drivers/usb/musb/musb_gadget.c | 6 +++--- drivers/usb/renesas_usbhs/mod_gadget.c | 4 ++-- include/linux/usb/gadget.h | 19 +++++++++++++++++++ 30 files changed, 92 insertions(+), 61 deletions(-) (limited to 'include/linux') diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index b34c81969cba..77e4a17cfb44 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1566,7 +1566,7 @@ static int init_eps(struct ci_hdrc *ci) * eps, maxP is set by epautoconfig() called * by gadget layer */ - hwep->ep.maxpacket = (unsigned short)~0; + usb_ep_set_maxpacket_limit(&hwep->ep, (unsigned short)~0); INIT_LIST_HEAD(&hwep->qh.queue); hwep->qh.ptr = dma_pool_alloc(ci->qh_pool, GFP_KERNEL, @@ -1586,7 +1586,7 @@ static int init_eps(struct ci_hdrc *ci) else ci->ep0in = hwep; - hwep->ep.maxpacket = CTRL_PAYLOAD_MAX; + usb_ep_set_maxpacket_limit(&hwep->ep, CTRL_PAYLOAD_MAX); continue; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index b85ec110d6a0..5401b2b573d5 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1653,7 +1653,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, dev_vdbg(dwc->dev, "initializing %s\n", dep->name); if (epnum == 0 || epnum == 1) { - dep->endpoint.maxpacket = 512; + usb_ep_set_maxpacket_limit(&dep->endpoint, 512); dep->endpoint.maxburst = 1; dep->endpoint.ops = &dwc3_gadget_ep0_ops; if (!epnum) @@ -1661,7 +1661,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, } else { int ret; - dep->endpoint.maxpacket = 1024; + usb_ep_set_maxpacket_limit(&dep->endpoint, 1024); dep->endpoint.max_streams = 15; dep->endpoint.ops = &dwc3_gadget_ep_ops; list_add_tail(&dep->endpoint.ep_list, diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index f0ff4a675e9d..a04aa8b64472 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -446,7 +446,7 @@ static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep) ep->ep.ops = &udc_ep_ops; INIT_LIST_HEAD(&ep->queue); - ep->ep.maxpacket = (u16) ~0; + usb_ep_set_maxpacket_limit(&ep->ep,(u16) ~0); /* set NAK */ tmp = readl(&ep->regs->ctl); tmp |= AMD_BIT(UDC_EPCTL_SNAK); @@ -1564,12 +1564,15 @@ static void udc_setup_endpoints(struct udc *dev) } /* EP0 max packet */ if (dev->gadget.speed == USB_SPEED_FULL) { - dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE; - dev->ep[UDC_EP0OUT_IX].ep.maxpacket = - UDC_FS_EP0OUT_MAX_PKT_SIZE; + usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IX].ep, + UDC_FS_EP0IN_MAX_PKT_SIZE); + usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IX].ep, + UDC_FS_EP0OUT_MAX_PKT_SIZE); } else if (dev->gadget.speed == USB_SPEED_HIGH) { - dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; - dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; + usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IX].ep, + UDC_EP0IN_MAX_PKT_SIZE); + usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IX].ep, + UDC_EP0OUT_MAX_PKT_SIZE); } /* diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 4cc4fd6d1473..0353b6471bde 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -834,7 +834,7 @@ static void udc_reinit(struct at91_udc *udc) ep->ep.desc = NULL; ep->stopped = 0; ep->fifo_bank = 0; - ep->ep.maxpacket = ep->maxpacket; + usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket); ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i); /* initialize one queue per endpoint */ INIT_LIST_HEAD(&ep->queue); @@ -1759,15 +1759,15 @@ static int at91udc_probe(struct platform_device *pdev) /* newer chips have more FIFO memory than rm9200 */ if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) { - udc->ep[0].maxpacket = 64; - udc->ep[3].maxpacket = 64; - udc->ep[4].maxpacket = 512; - udc->ep[5].maxpacket = 512; + usb_ep_set_maxpacket_limit(&udc->ep[0], 64); + usb_ep_set_maxpacket_limit(&udc->ep[3], 64); + usb_ep_set_maxpacket_limit(&udc->ep[4], 512); + usb_ep_set_maxpacket_limit(&udc->ep[5], 512); } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) { - udc->ep[3].maxpacket = 64; + usb_ep_set_maxpacket_limit(&udc->ep[3], 64); } else if (cpu_is_at91sam9263()) { - udc->ep[0].maxpacket = 64; - udc->ep[3].maxpacket = 64; + usb_ep_set_maxpacket_limit(&udc->ep[0], 64); + usb_ep_set_maxpacket_limit(&udc->ep[3], 64); } udc->udp_baseaddr = ioremap(res->start, resource_size(res)); diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 2cb52e0438df..68cf3a40f98e 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -1904,7 +1904,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, ep->dma_regs = udc->regs + USBA_DMA_BASE(i); ep->fifo = udc->fifo + USBA_FIFO_BASE(i); ep->ep.ops = &usba_ep_ops; - ep->ep.maxpacket = ep->fifo_size; + usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size); ep->udc = udc; INIT_LIST_HEAD(&ep->queue); @@ -1957,7 +1957,8 @@ static struct usba_ep * usba_udc_pdata(struct platform_device *pdev, ep->fifo = udc->fifo + USBA_FIFO_BASE(i); ep->ep.ops = &usba_ep_ops; ep->ep.name = pdata->ep[i].name; - ep->fifo_size = ep->ep.maxpacket = pdata->ep[i].fifo_size; + ep->fifo_size = pdata->ep[i].fifo_size; + usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size); ep->udc = udc; INIT_LIST_HEAD(&ep->queue); ep->nr_banks = pdata->ep[i].nr_banks; diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c index c58fcf1ebe41..2ac7a8f4bfff 100644 --- a/drivers/usb/gadget/bcm63xx_udc.c +++ b/drivers/usb/gadget/bcm63xx_udc.c @@ -549,7 +549,7 @@ static void bcm63xx_ep_setup(struct bcm63xx_udc *udc) if (idx < 0) continue; - udc->bep[idx].ep.maxpacket = max_pkt; + usb_ep_set_maxpacket_limit(&udc->bep[idx].ep, max_pkt); val = (idx << USBD_CSR_EP_LOG_SHIFT) | (cfg->dir << USBD_CSR_EP_DIR_SHIFT) | @@ -943,7 +943,7 @@ static int bcm63xx_init_udc_hw(struct bcm63xx_udc *udc) bep->ep.ops = &bcm63xx_udc_ep_ops; list_add_tail(&bep->ep.ep_list, &udc->gadget.ep_list); bep->halted = 0; - bep->ep.maxpacket = BCM63XX_MAX_CTRL_PKT; + usb_ep_set_maxpacket_limit(&bep->ep, BCM63XX_MAX_CTRL_PKT); bep->udc = udc; bep->ep.desc = NULL; INIT_LIST_HEAD(&bep->queue); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 8f4dae310923..8c06430dcc47 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -951,7 +951,7 @@ static void init_dummy_udc_hw(struct dummy *dum) list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list); ep->halted = ep->wedged = ep->already_seen = ep->setup_stage = 0; - ep->ep.maxpacket = ~0; + usb_ep_set_maxpacket_limit(&ep->ep, ~0); ep->ep.max_streams = 16; ep->last_io = jiffies; ep->gadget = &dum->gadget; diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c index feaaa7b72ee3..358de320afb0 100644 --- a/drivers/usb/gadget/epautoconf.c +++ b/drivers/usb/gadget/epautoconf.c @@ -129,7 +129,7 @@ ep_matches ( * and wants to know the maximum possible, provide the info. */ if (desc->wMaxPacketSize == 0) - desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket); + desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit); /* endpoint maxpacket size is an input parameter, except for bulk * where it's an output parameter representing the full speed limit. @@ -145,7 +145,7 @@ ep_matches ( case USB_ENDPOINT_XFER_ISOC: /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ - if (ep->maxpacket < max) + if (ep->maxpacket_limit < max) return 0; if (!gadget_is_dualspeed(gadget) && max > 1023) return 0; @@ -178,7 +178,7 @@ ep_matches ( /* report (variable) full speed bulk maxpacket */ if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) { - int size = ep->maxpacket; + int size = ep->maxpacket_limit; /* min() doesn't work on bitfields with gcc-3.5 */ if (size > 64) diff --git a/drivers/usb/gadget/fotg210-udc.c b/drivers/usb/gadget/fotg210-udc.c index bbbfd1948778..2d0305280e8c 100644 --- a/drivers/usb/gadget/fotg210-udc.c +++ b/drivers/usb/gadget/fotg210-udc.c @@ -1157,8 +1157,9 @@ static int fotg210_udc_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ep->queue); ep->ep.name = fotg210_ep_name[i]; ep->ep.ops = &fotg210_ep_ops; + usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); } - fotg210->ep[0]->ep.maxpacket = 0x40; + usb_ep_set_maxpacket_limit(&fotg210->ep[0]->ep, 0x40); fotg210->gadget.ep0 = &fotg210->ep[0]->ep; INIT_LIST_HEAD(&fotg210->gadget.ep0->ep_list); diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 6315ee698d4d..f60d4da8f2c0 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -2429,7 +2429,7 @@ static int qe_ep_config(struct qe_udc *udc, unsigned char pipe_num) ep->ep.ops = &qe_ep_ops; ep->stopped = 1; - ep->ep.maxpacket = (unsigned short) ~0; + usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); ep->ep.desc = NULL; ep->dir = 0xff; ep->epnum = (u8)pipe_num; diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index b7dea4eec32c..15960af0f67e 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -2311,7 +2311,7 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index, /* for ep0: maxP defined in desc * for other eps, maxP is set by epautoconfig() called by gadget layer */ - ep->ep.maxpacket = (unsigned short) ~0; + usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); /* the queue lists any req for this ep */ INIT_LIST_HEAD(&ep->queue); @@ -2469,7 +2469,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev) * for other eps, gadget layer called ep_enable with defined desc */ udc_controller->eps[0].ep.desc = &fsl_ep0_desc; - udc_controller->eps[0].ep.maxpacket = USB_MAX_CTRL_PAYLOAD; + usb_ep_set_maxpacket_limit(&udc_controller->eps[0].ep, + USB_MAX_CTRL_PAYLOAD); /* setup the udc->eps[] for non-control endpoints and link * to gadget.ep_list */ diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index b278abe52453..6423f1840ed9 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -1452,9 +1452,9 @@ static int __init fusb300_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ep->queue); ep->ep.name = fusb300_ep_name[i]; ep->ep.ops = &fusb300_ep_ops; - ep->ep.maxpacket = HS_BULK_MAX_PACKET_SIZE; + usb_ep_set_maxpacket_limit(&ep->ep, HS_BULK_MAX_PACKET_SIZE); } - fusb300->ep[0]->ep.maxpacket = HS_CTL_MAX_PACKET_SIZE; + usb_ep_set_maxpacket_limit(&fusb300->ep[0]->ep, HS_CTL_MAX_PACKET_SIZE); fusb300->ep[0]->epnum = 0; fusb300->gadget.ep0 = &fusb300->ep[0]->ep; INIT_LIST_HEAD(&fusb300->gadget.ep0->ep_list); diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index 7eda9fd6528e..f66f3a7a35ef 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -231,7 +231,7 @@ static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep) } } - ep->ep.maxpacket = MAX_FIFO_SIZE; + usb_ep_set_maxpacket_limit(&ep->ep, MAX_FIFO_SIZE); ep->ep.desc = NULL; ep->stopped = 1; ep->irqs = 0; @@ -1251,7 +1251,7 @@ static void udc_reinit (struct goku_udc *dev) } dev->ep[0].reg_mode = NULL; - dev->ep[0].ep.maxpacket = MAX_EP0_SIZE; + usb_ep_set_maxpacket_limit(&dev->ep[0].ep, MAX_EP0_SIZE); list_del_init (&dev->ep[0].ep.ep_list); } diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c index 6a2a65aa0057..049ebab0d360 100644 --- a/drivers/usb/gadget/lpc32xx_udc.c +++ b/drivers/usb/gadget/lpc32xx_udc.c @@ -1449,7 +1449,7 @@ static void udc_reinit(struct lpc32xx_udc *udc) if (i != 0) list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - ep->ep.maxpacket = ep->maxpacket; + usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket); INIT_LIST_HEAD(&ep->queue); ep->req_pending = 0; } diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index d5f050d30edf..8cae01d88597 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -1647,9 +1647,9 @@ static int __init m66592_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ep->queue); ep->ep.name = m66592_ep_name[i]; ep->ep.ops = &m66592_ep_ops; - ep->ep.maxpacket = 512; + usb_ep_set_maxpacket_limit(&ep->ep, 512); } - m66592->ep[0].ep.maxpacket = 64; + usb_ep_set_maxpacket_limit(&m66592->ep[0].ep, 64); m66592->ep[0].pipenum = 0; m66592->ep[0].fifoaddr = M66592_CFIFO; m66592->ep[0].fifosel = M66592_CFIFOSEL; diff --git a/drivers/usb/gadget/mv_u3d_core.c b/drivers/usb/gadget/mv_u3d_core.c index 234711eabea1..9fe31d7dded6 100644 --- a/drivers/usb/gadget/mv_u3d_core.c +++ b/drivers/usb/gadget/mv_u3d_core.c @@ -1336,7 +1336,7 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d) ep->ep.name = ep->name; ep->ep.ops = &mv_u3d_ep_ops; ep->wedge = 0; - ep->ep.maxpacket = MV_U3D_EP0_MAX_PKT_SIZE; + usb_ep_set_maxpacket_limit(&ep->ep, MV_U3D_EP0_MAX_PKT_SIZE); ep->ep_num = 0; ep->ep.desc = &mv_u3d_ep0_desc; INIT_LIST_HEAD(&ep->queue); @@ -1361,7 +1361,7 @@ static int mv_u3d_eps_init(struct mv_u3d *u3d) ep->ep.name = ep->name; ep->ep.ops = &mv_u3d_ep_ops; - ep->ep.maxpacket = (unsigned short) ~0; + usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); ep->ep_num = i / 2; INIT_LIST_HEAD(&ep->queue); diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index 104cdbea635a..d43ce95fc4bd 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -1261,7 +1261,7 @@ static int eps_init(struct mv_udc *udc) ep->ep.ops = &mv_ep_ops; ep->wedge = 0; ep->stopped = 0; - ep->ep.maxpacket = EP0_MAX_PKT_SIZE; + usb_ep_set_maxpacket_limit(&ep->ep, EP0_MAX_PKT_SIZE); ep->ep_num = 0; ep->ep.desc = &mv_ep0_desc; INIT_LIST_HEAD(&ep->queue); @@ -1284,7 +1284,7 @@ static int eps_init(struct mv_udc *udc) ep->ep.ops = &mv_ep_ops; ep->stopped = 0; - ep->ep.maxpacket = (unsigned short) ~0; + usb_ep_set_maxpacket_limit(&ep->ep, (unsigned short) ~0); ep->ep_num = i / 2; INIT_LIST_HEAD(&ep->queue); diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c index bf2bb39f35a2..ca15405583e2 100644 --- a/drivers/usb/gadget/net2272.c +++ b/drivers/usb/gadget/net2272.c @@ -266,7 +266,7 @@ static void net2272_ep_reset(struct net2272_ep *ep) ep->desc = NULL; INIT_LIST_HEAD(&ep->queue); - ep->ep.maxpacket = ~0; + usb_ep_set_maxpacket_limit(&ep->ep, ~0); ep->ep.ops = &net2272_ep_ops; /* disable irqs, endpoint */ @@ -1409,7 +1409,7 @@ net2272_usb_reinit(struct net2272 *dev) ep->fifo_size = 64; net2272_ep_reset(ep); } - dev->ep[0].ep.maxpacket = 64; + usb_ep_set_maxpacket_limit(&dev->ep[0].ep, 64); dev->gadget.ep0 = &dev->ep[0].ep; dev->ep[0].stopped = 0; diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index fc852177c087..43e5e2f9888f 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -293,7 +293,7 @@ static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep) ep->desc = NULL; INIT_LIST_HEAD (&ep->queue); - ep->ep.maxpacket = ~0; + usb_ep_set_maxpacket_limit(&ep->ep, ~0); ep->ep.ops = &net2280_ep_ops; /* disable the dma, irqs, endpoint... */ @@ -1805,9 +1805,9 @@ static void usb_reinit (struct net2280 *dev) ep->regs = &dev->epregs [tmp]; ep_reset (dev->regs, ep); } - dev->ep [0].ep.maxpacket = 64; - dev->ep [5].ep.maxpacket = 64; - dev->ep [6].ep.maxpacket = 64; + usb_ep_set_maxpacket_limit(&dev->ep [0].ep, 64); + usb_ep_set_maxpacket_limit(&dev->ep [5].ep, 64); + usb_ep_set_maxpacket_limit(&dev->ep [6].ep, 64); dev->gadget.ep0 = &dev->ep [0].ep; dev->ep [0].stopped = 0; diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 83957cc225d9..34bd713065c5 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2586,7 +2586,8 @@ omap_ep_setup(char *name, u8 addr, u8 type, ep->ep.name = ep->name; ep->ep.ops = &omap_ep_ops; - ep->ep.maxpacket = ep->maxpacket = maxp; + ep->maxpacket = maxp; + usb_ep_set_maxpacket_limit(&ep->ep, ep->maxpacket); list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); return buf; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 78a3d9289816..eb8c3bedb57a 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -2896,12 +2896,12 @@ static void pch_udc_pcd_reinit(struct pch_udc_dev *dev) ep->offset_addr = (UDC_EPINT_OUT_SHIFT + ep->num) * UDC_EP_REG_SHIFT; /* need to set ep->ep.maxpacket and set Default Configuration?*/ - ep->ep.maxpacket = UDC_BULK_MAX_PKT_SIZE; + usb_ep_set_maxpacket_limit(&ep->ep, UDC_BULK_MAX_PKT_SIZE); list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); INIT_LIST_HEAD(&ep->queue); } - dev->ep[UDC_EP0IN_IDX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; - dev->ep[UDC_EP0OUT_IDX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; + usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0IN_IDX].ep, UDC_EP0IN_MAX_PKT_SIZE); + usb_ep_set_maxpacket_limit(&dev->ep[UDC_EP0OUT_IDX].ep, UDC_EP0OUT_MAX_PKT_SIZE); /* remove ep0 in and out from the list. They have own pointer */ list_del_init(&dev->ep[UDC_EP0IN_IDX].ep.ep_list); diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 0ac6064aa3b8..5b4f43730d8b 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -1193,6 +1193,7 @@ static void udc_reinit(struct pxa25x_udc *dev) ep->stopped = 0; INIT_LIST_HEAD (&ep->queue); ep->pio_irqs = 0; + usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket); } /* the rest was statically initialized, and is read-only */ diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 3c97da7760da..cdf4d678be96 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -1737,9 +1737,12 @@ static void udc_init_data(struct pxa_udc *dev) } /* USB endpoints init */ - for (i = 1; i < NR_USB_ENDPOINTS; i++) + for (i = 1; i < NR_USB_ENDPOINTS; i++) { list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list, &dev->gadget.ep_list); + usb_ep_set_maxpacket_limit(&dev->udc_usb_ep[i].usb_ep, + dev->udc_usb_ep[i].usb_ep.maxpacket); + } } /** diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 47287518bff3..aff0a6718bc6 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -1964,9 +1964,9 @@ static int __init r8a66597_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ep->queue); ep->ep.name = r8a66597_ep_name[i]; ep->ep.ops = &r8a66597_ep_ops; - ep->ep.maxpacket = 512; + usb_ep_set_maxpacket_limit(&ep->ep, 512); } - r8a66597->ep[0].ep.maxpacket = 64; + usb_ep_set_maxpacket_limit(&r8a66597->ep[0].ep, 64); r8a66597->ep[0].pipenum = 0; r8a66597->ep[0].fifoaddr = CFIFO; r8a66597->ep[0].fifosel = CFIFOSEL; diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 6c80bfcefa87..50df18d1f1cf 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -3150,7 +3150,7 @@ static void s3c_hsotg_initep(struct s3c_hsotg *hsotg, hs_ep->parent = hsotg; hs_ep->ep.name = hs_ep->name; - hs_ep->ep.maxpacket = epnum ? 1024 : EP0_MPS_LIMIT; + usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT); hs_ep->ep.ops = &s3c_hsotg_ep_ops; /* diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index 1a1a41498db2..ea4bbfe72ec0 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -999,7 +999,7 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc, hsep->dev = hsudc; hsep->ep.name = hsep->name; - hsep->ep.maxpacket = epnum ? 512 : 64; + usb_ep_set_maxpacket_limit(&hsep->ep, epnum ? 512 : 64); hsep->ep.ops = &s3c_hsudc_ep_ops; hsep->fifo = hsudc->regs + S3C_BR(epnum); hsep->ep.desc = NULL; diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index c72d810e6b36..f04b2c3154de 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1629,6 +1629,7 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev) ep->ep.desc = NULL; ep->halted = 0; INIT_LIST_HEAD(&ep->queue); + usb_ep_set_maxpacket_limit(&ep->ep, &ep->ep.maxpacket); } } diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index d2d3a173b315..76f007654821 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1727,14 +1727,14 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in) ep->end_point.name = ep->name; INIT_LIST_HEAD(&ep->end_point.ep_list); if (!epnum) { - ep->end_point.maxpacket = 64; + usb_ep_set_maxpacket_limit(&ep->end_point, 64); ep->end_point.ops = &musb_g_ep0_ops; musb->g.ep0 = &ep->end_point; } else { if (is_in) - ep->end_point.maxpacket = hw_ep->max_packet_sz_tx; + usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_tx); else - ep->end_point.maxpacket = hw_ep->max_packet_sz_rx; + usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_rx); ep->end_point.ops = &musb_ep_ops; list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list); } diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 3385aeb5a364..458f3766bef1 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -987,11 +987,11 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv) /* init DCP */ if (usbhsg_is_dcp(uep)) { gpriv->gadget.ep0 = &uep->ep; - uep->ep.maxpacket = 64; + usb_ep_set_maxpacket_limit(&uep->ep, 64); } /* init normal pipe */ else { - uep->ep.maxpacket = 512; + usb_ep_set_maxpacket_limit(&uep->ep, 512); list_add_tail(&uep->ep.ep_list, &gpriv->gadget.ep_list); } } diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index cae8a6216551..c3a61853cd13 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -148,6 +148,9 @@ struct usb_ep_ops { * @maxpacket:The maximum packet size used on this endpoint. The initial * value can sometimes be reduced (hardware allowing), according to * the endpoint descriptor used to configure the endpoint. + * @maxpacket_limit:The maximum packet size value which can be handled by this + * endpoint. It's set once by UDC driver when endpoint is initialized, and + * should not be changed. Should not be confused with maxpacket. * @max_streams: The maximum number of streams supported * by this EP (0 - 16, actual number is 2^n) * @mult: multiplier, 'mult' value for SS Isoc EPs @@ -171,6 +174,7 @@ struct usb_ep { const struct usb_ep_ops *ops; struct list_head ep_list; unsigned maxpacket:16; + unsigned maxpacket_limit:16; unsigned max_streams:16; unsigned mult:2; unsigned maxburst:5; @@ -181,6 +185,21 @@ struct usb_ep { /*-------------------------------------------------------------------------*/ +/** + * usb_ep_set_maxpacket_limit - set maximum packet size limit for endpoint + * @ep:the endpoint being configured + * @maxpacket_limit:value of maximum packet size limit + * + * This function shoud be used only in UDC drivers to initialize endpoint + * (usually in probe function). + */ +static inline void usb_ep_set_maxpacket_limit(struct usb_ep *ep, + unsigned maxpacket_limit) +{ + ep->maxpacket_limit = maxpacket_limit; + ep->maxpacket = maxpacket_limit; +} + /** * usb_ep_enable - configure endpoint, making it usable * @ep:the endpoint being configured. may not be the endpoint named "ep0". -- cgit v1.2.3-59-g8ed1b From 71ae8aac3e198c6f3577cb7ad3a17f6128e97bfa Mon Sep 17 00:00:00 2001 From: Francesco Fusco Date: Thu, 12 Dec 2013 16:09:05 +0100 Subject: lib: introduce arch optimized hash library We introduce a new hashing library that is meant to be used in the contexts where speed is more important than uniformity of the hashed values. The hash library leverages architecture specific implementation to achieve high performance and fall backs to jhash() for the generic case. On Intel-based x86 architectures, the library can exploit the crc32l instruction, part of the Intel SSE4.2 instruction set, if the instruction is supported by the processor. This implementation is twice as fast as the jhash() implementation on an i7 processor. Additional architectures, such as Arm64 provide instructions for accelerating the computation of CRC, so they could be added as well in follow-up work. Signed-off-by: Francesco Fusco Signed-off-by: Daniel Borkmann Signed-off-by: Thomas Graf Cc: linux-kernel@vger.kernel.org Signed-off-by: David S. Miller --- arch/x86/include/asm/hash.h | 7 ++++ arch/x86/lib/Makefile | 2 +- arch/x86/lib/hash.c | 88 +++++++++++++++++++++++++++++++++++++++++++++ include/asm-generic/hash.h | 9 +++++ include/linux/hash.h | 36 +++++++++++++++++++ lib/Makefile | 2 +- lib/hash.c | 38 ++++++++++++++++++++ 7 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 arch/x86/include/asm/hash.h create mode 100644 arch/x86/lib/hash.c create mode 100644 include/asm-generic/hash.h create mode 100644 lib/hash.c (limited to 'include/linux') diff --git a/arch/x86/include/asm/hash.h b/arch/x86/include/asm/hash.h new file mode 100644 index 000000000000..e8c58f88b1d4 --- /dev/null +++ b/arch/x86/include/asm/hash.h @@ -0,0 +1,7 @@ +#ifndef _ASM_X86_HASH_H +#define _ASM_X86_HASH_H + +struct fast_hash_ops; +extern void setup_arch_fast_hash(struct fast_hash_ops *ops); + +#endif /* _ASM_X86_HASH_H */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 992d63bb154f..eabcb6e6a900 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -24,7 +24,7 @@ lib-$(CONFIG_SMP) += rwlock.o lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o -obj-y += msr.o msr-reg.o msr-reg-export.o +obj-y += msr.o msr-reg.o msr-reg-export.o hash.o ifeq ($(CONFIG_X86_32),y) obj-y += atomic64_32.o diff --git a/arch/x86/lib/hash.c b/arch/x86/lib/hash.c new file mode 100644 index 000000000000..3056702e81fb --- /dev/null +++ b/arch/x86/lib/hash.c @@ -0,0 +1,88 @@ +/* + * Some portions derived from code covered by the following notice: + * + * Copyright (c) 2010-2013 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include +#include +#include + +static inline u32 crc32_u32(u32 crc, u32 val) +{ + asm ("crc32l %1,%0\n" : "+r" (crc) : "rm" (val)); + return crc; +} + +static u32 intel_crc4_2_hash(const void *data, u32 len, u32 seed) +{ + const u32 *p32 = (const u32 *) data; + u32 i, tmp = 0; + + for (i = 0; i < len / 4; i++) + seed = crc32_u32(*p32++, seed); + + switch (3 - (len & 0x03)) { + case 0: + tmp |= *((const u8 *) p32 + 2) << 16; + /* fallthrough */ + case 1: + tmp |= *((const u8 *) p32 + 1) << 8; + /* fallthrough */ + case 2: + tmp |= *((const u8 *) p32); + seed = crc32_u32(tmp, seed); + default: + break; + } + + return seed; +} + +static u32 intel_crc4_2_hash2(const u32 *data, u32 len, u32 seed) +{ + const u32 *p32 = (const u32 *) data; + u32 i; + + for (i = 0; i < len; i++) + seed = crc32_u32(*p32++, seed); + + return seed; +} + +void setup_arch_fast_hash(struct fast_hash_ops *ops) +{ + if (cpu_has_xmm4_2) { + ops->hash = intel_crc4_2_hash; + ops->hash2 = intel_crc4_2_hash2; + } +} diff --git a/include/asm-generic/hash.h b/include/asm-generic/hash.h new file mode 100644 index 000000000000..05cb3421ee7e --- /dev/null +++ b/include/asm-generic/hash.h @@ -0,0 +1,9 @@ +#ifndef __ASM_GENERIC_HASH_H +#define __ASM_GENERIC_HASH_H + +struct arch_hash_ops; +static inline void setup_arch_fast_hash(struct arch_hash_ops *ops) +{ +} + +#endif /* __ASM_GENERIC_HASH_H */ diff --git a/include/linux/hash.h b/include/linux/hash.h index f09a0ae4d858..bd1754c7ecef 100644 --- a/include/linux/hash.h +++ b/include/linux/hash.h @@ -15,6 +15,7 @@ */ #include +#include #include /* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */ @@ -78,4 +79,39 @@ static inline u32 hash32_ptr(const void *ptr) #endif return (u32)val; } + +struct fast_hash_ops { + u32 (*hash)(const void *data, u32 len, u32 seed); + u32 (*hash2)(const u32 *data, u32 len, u32 seed); +}; + +/** + * arch_fast_hash - Caclulates a hash over a given buffer that can have + * arbitrary size. This function will eventually use an + * architecture-optimized hashing implementation if + * available, and trades off distribution for speed. + * + * @data: buffer to hash + * @len: length of buffer in bytes + * @seed: start seed + * + * Returns 32bit hash. + */ +extern u32 arch_fast_hash(const void *data, u32 len, u32 seed); + +/** + * arch_fast_hash2 - Caclulates a hash over a given buffer that has a + * size that is of a multiple of 32bit words. This + * function will eventually use an architecture- + * optimized hashing implementation if available, + * and trades off distribution for speed. + * + * @data: buffer to hash (must be 32bit padded) + * @len: number of 32bit words + * @seed: start seed + * + * Returns 32bit hash. + */ +extern u32 arch_fast_hash2(const u32 *data, u32 len, u32 seed); + #endif /* _LINUX_HASH_H */ diff --git a/lib/Makefile b/lib/Makefile index a459c31e8c6b..d0f79c547d97 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -26,7 +26,7 @@ obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \ gcd.o lcm.o list_sort.o uuid.o flex_array.o iovec.o clz_ctz.o \ bsearch.o find_last_bit.o find_next_bit.o llist.o memweight.o kfifo.o \ - percpu-refcount.o percpu_ida.o + percpu-refcount.o percpu_ida.o hash.o obj-y += string_helpers.o obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o obj-y += kstrtox.o diff --git a/lib/hash.c b/lib/hash.c new file mode 100644 index 000000000000..b89f06a2d606 --- /dev/null +++ b/lib/hash.c @@ -0,0 +1,38 @@ +/* General purpose hashing library + * + * That's a start of a kernel hashing library, which can be extended + * with further algorithms in future. arch_fast_hash{2,}() will + * eventually resolve to an architecture optimized implementation. + * + * Copyright 2013 Francesco Fusco + * Copyright 2013 Daniel Borkmann + * Copyright 2013 Thomas Graf + * Licensed under the GNU General Public License, version 2.0 (GPLv2) + */ + +#include +#include + +static struct fast_hash_ops arch_hash_ops __read_mostly = { + .hash = jhash, + .hash2 = jhash2, +}; + +u32 arch_fast_hash(const void *data, u32 len, u32 seed) +{ + return arch_hash_ops.hash(data, len, seed); +} +EXPORT_SYMBOL_GPL(arch_fast_hash); + +u32 arch_fast_hash2(const u32 *data, u32 len, u32 seed) +{ + return arch_hash_ops.hash2(data, len, seed); +} +EXPORT_SYMBOL_GPL(arch_fast_hash2); + +static int __init hashlib_init(void) +{ + setup_arch_fast_hash(&arch_hash_ops); + return 0; +} +early_initcall(hashlib_init); -- cgit v1.2.3-59-g8ed1b From 481b5d938b4a60f052d7e15965a8417125e0d39f Mon Sep 17 00:00:00 2001 From: Sebastian Hesselbarth Date: Fri, 13 Dec 2013 10:20:27 +0100 Subject: net: phy: provide phy_resume/phy_suspend helpers This adds helper functions to resume and suspend a given phy_device by calling the corresponding driver callbacks if available. Signed-off-by: Sebastian Hesselbarth Acked-by: Mugunthan V N Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 24 ++++++++++++++++++++++++ include/linux/phy.h | 2 ++ 2 files changed, 26 insertions(+) (limited to 'include/linux') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 5a619f0dcf73..91f17178f1b3 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -679,6 +679,30 @@ void phy_detach(struct phy_device *phydev) } EXPORT_SYMBOL(phy_detach); +int phy_suspend(struct phy_device *phydev) +{ + struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver); + struct ethtool_wolinfo wol; + + /* If the device has WOL enabled, we cannot suspend the PHY */ + wol.cmd = ETHTOOL_GWOL; + phy_ethtool_get_wol(phydev, &wol); + if (wol.wolopts) + return -EBUSY; + + if (phydrv->suspend) + return phydrv->suspend(phydev); + return 0; +} + +int phy_resume(struct phy_device *phydev) +{ + struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver); + + if (phydrv->resume) + return phydrv->resume(phydev); + return 0; +} /* Generic PHY support and helper functions */ diff --git a/include/linux/phy.h b/include/linux/phy.h index 90a666e0884b..73384ff3b5e5 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -548,6 +548,8 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45); int phy_device_register(struct phy_device *phy); int phy_init_hw(struct phy_device *phydev); +int phy_suspend(struct phy_device *phydev); +int phy_resume(struct phy_device *phydev); struct phy_device * phy_attach(struct net_device *dev, const char *bus_id, phy_interface_t interface); struct phy_device *phy_find_first(struct mii_bus *bus); -- cgit v1.2.3-59-g8ed1b From 477bb93320cec7ae74d5ccfad4f2bfa0b28fbe90 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Fri, 13 Dec 2013 12:35:56 -0800 Subject: net: remove dead code for add/del multiple These function to manipulate multiple addresses are not used anywhere in current net-next tree. Some out of tree code maybe using these but too bad; they should submit their code upstream.. Also, make __hw_addr_flush local since only used by dev_addr_lists.c Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/netdevice.h | 11 ------ net/core/dev_addr_lists.c | 97 +---------------------------------------------- 2 files changed, 1 insertion(+), 107 deletions(-) (limited to 'include/linux') diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 2c74d20dad34..a0dfcc8c002b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2810,17 +2810,10 @@ int register_netdev(struct net_device *dev); void unregister_netdev(struct net_device *dev); /* General hardware address lists handling functions */ -int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list, - struct netdev_hw_addr_list *from_list, - int addr_len, unsigned char addr_type); -void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list, - struct netdev_hw_addr_list *from_list, - int addr_len, unsigned char addr_type); int __hw_addr_sync(struct netdev_hw_addr_list *to_list, struct netdev_hw_addr_list *from_list, int addr_len); void __hw_addr_unsync(struct netdev_hw_addr_list *to_list, struct netdev_hw_addr_list *from_list, int addr_len); -void __hw_addr_flush(struct netdev_hw_addr_list *list); void __hw_addr_init(struct netdev_hw_addr_list *list); /* Functions used for device addresses handling */ @@ -2828,10 +2821,6 @@ int dev_addr_add(struct net_device *dev, const unsigned char *addr, unsigned char addr_type); int dev_addr_del(struct net_device *dev, const unsigned char *addr, unsigned char addr_type); -int dev_addr_add_multiple(struct net_device *to_dev, - struct net_device *from_dev, unsigned char addr_type); -int dev_addr_del_multiple(struct net_device *to_dev, - struct net_device *from_dev, unsigned char addr_type); void dev_addr_flush(struct net_device *dev); int dev_addr_init(struct net_device *dev); diff --git a/net/core/dev_addr_lists.c b/net/core/dev_addr_lists.c index ec40a849fc42..bb504a919e33 100644 --- a/net/core/dev_addr_lists.c +++ b/net/core/dev_addr_lists.c @@ -186,47 +186,6 @@ static int __hw_addr_sync_multiple(struct netdev_hw_addr_list *to_list, return err; } -int __hw_addr_add_multiple(struct netdev_hw_addr_list *to_list, - struct netdev_hw_addr_list *from_list, - int addr_len, unsigned char addr_type) -{ - int err; - struct netdev_hw_addr *ha, *ha2; - unsigned char type; - - list_for_each_entry(ha, &from_list->list, list) { - type = addr_type ? addr_type : ha->type; - err = __hw_addr_add(to_list, ha->addr, addr_len, type); - if (err) - goto unroll; - } - return 0; - -unroll: - list_for_each_entry(ha2, &from_list->list, list) { - if (ha2 == ha) - break; - type = addr_type ? addr_type : ha2->type; - __hw_addr_del(to_list, ha2->addr, addr_len, type); - } - return err; -} -EXPORT_SYMBOL(__hw_addr_add_multiple); - -void __hw_addr_del_multiple(struct netdev_hw_addr_list *to_list, - struct netdev_hw_addr_list *from_list, - int addr_len, unsigned char addr_type) -{ - struct netdev_hw_addr *ha; - unsigned char type; - - list_for_each_entry(ha, &from_list->list, list) { - type = addr_type ? addr_type : ha->type; - __hw_addr_del(to_list, ha->addr, addr_len, type); - } -} -EXPORT_SYMBOL(__hw_addr_del_multiple); - /* This function only works where there is a strict 1-1 relationship * between source and destionation of they synch. If you ever need to * sync addresses to more then 1 destination, you need to use @@ -264,7 +223,7 @@ void __hw_addr_unsync(struct netdev_hw_addr_list *to_list, } EXPORT_SYMBOL(__hw_addr_unsync); -void __hw_addr_flush(struct netdev_hw_addr_list *list) +static void __hw_addr_flush(struct netdev_hw_addr_list *list) { struct netdev_hw_addr *ha, *tmp; @@ -274,7 +233,6 @@ void __hw_addr_flush(struct netdev_hw_addr_list *list) } list->count = 0; } -EXPORT_SYMBOL(__hw_addr_flush); void __hw_addr_init(struct netdev_hw_addr_list *list) { @@ -400,59 +358,6 @@ int dev_addr_del(struct net_device *dev, const unsigned char *addr, } EXPORT_SYMBOL(dev_addr_del); -/** - * dev_addr_add_multiple - Add device addresses from another device - * @to_dev: device to which addresses will be added - * @from_dev: device from which addresses will be added - * @addr_type: address type - 0 means type will be used from from_dev - * - * Add device addresses of the one device to another. - ** - * The caller must hold the rtnl_mutex. - */ -int dev_addr_add_multiple(struct net_device *to_dev, - struct net_device *from_dev, - unsigned char addr_type) -{ - int err; - - ASSERT_RTNL(); - - if (from_dev->addr_len != to_dev->addr_len) - return -EINVAL; - err = __hw_addr_add_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs, - to_dev->addr_len, addr_type); - if (!err) - call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); - return err; -} -EXPORT_SYMBOL(dev_addr_add_multiple); - -/** - * dev_addr_del_multiple - Delete device addresses by another device - * @to_dev: device where the addresses will be deleted - * @from_dev: device supplying the addresses to be deleted - * @addr_type: address type - 0 means type will be used from from_dev - * - * Deletes addresses in to device by the list of addresses in from device. - * - * The caller must hold the rtnl_mutex. - */ -int dev_addr_del_multiple(struct net_device *to_dev, - struct net_device *from_dev, - unsigned char addr_type) -{ - ASSERT_RTNL(); - - if (from_dev->addr_len != to_dev->addr_len) - return -EINVAL; - __hw_addr_del_multiple(&to_dev->dev_addrs, &from_dev->dev_addrs, - to_dev->addr_len, addr_type); - call_netdevice_notifiers(NETDEV_CHANGEADDR, to_dev); - return 0; -} -EXPORT_SYMBOL(dev_addr_del_multiple); - /* * Unicast list handling functions */ -- cgit v1.2.3-59-g8ed1b From 3958afa1b272eb07109fd31549e69193b4d7c364 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Sun, 15 Dec 2013 22:12:06 -0800 Subject: net: Change skb_get_rxhash to skb_get_hash Changing name of function as part of making the hash in skbuff to be generic property, not just for receive path. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/macvtap.c | 2 +- drivers/net/tun.c | 4 ++-- drivers/net/vxlan.c | 2 +- include/linux/skbuff.h | 6 +++--- net/core/dev.c | 4 ++-- net/core/flow_dissector.c | 6 +++--- net/packet/af_packet.c | 4 ++-- net/sched/cls_flow.c | 2 +- net/sched/em_meta.c | 2 +- net/sched/sch_fq.c | 2 +- 10 files changed, 17 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 64409af0da31..431f58cb2ceb 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -224,7 +224,7 @@ static struct macvtap_queue *macvtap_get_queue(struct net_device *dev, goto out; /* Check if we can use flow to select a queue */ - rxq = skb_get_rxhash(skb); + rxq = skb_get_hash(skb); if (rxq) { tap = rcu_dereference(vlan->taps[rxq % numvtaps]); goto out; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 3c5a8d8cde50..8569da248336 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -358,7 +358,7 @@ static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb) rcu_read_lock(); numqueues = ACCESS_ONCE(tun->numqueues); - txq = skb_get_rxhash(skb); + txq = skb_get_hash(skb); if (txq) { e = tun_flow_find(&tun->flows[tun_hashfn(txq)], txq); if (e) @@ -1146,7 +1146,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, skb_reset_network_header(skb); skb_probe_transport_header(skb, 0); - rxhash = skb_get_rxhash(skb); + rxhash = skb_get_hash(skb); netif_rx_ni(skb); tun->dev->stats.rx_packets++; diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 58f6a0c02b17..b247a7a29366 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1405,7 +1405,7 @@ __be16 vxlan_src_port(__u16 port_min, __u16 port_max, struct sk_buff *skb) unsigned int range = (port_max - port_min) + 1; u32 hash; - hash = skb_get_rxhash(skb); + hash = skb_get_hash(skb); if (!hash) hash = jhash(skb->data, 2 * ETH_ALEN, (__force u32) skb->protocol); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 77c7aae1c6b2..4725b953e00d 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -703,11 +703,11 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, unsigned int to, struct ts_config *config, struct ts_state *state); -void __skb_get_rxhash(struct sk_buff *skb); -static inline __u32 skb_get_rxhash(struct sk_buff *skb) +void __skb_get_hash(struct sk_buff *skb); +static inline __u32 skb_get_hash(struct sk_buff *skb) { if (!skb->l4_rxhash) - __skb_get_rxhash(skb); + __skb_get_hash(skb); return skb->rxhash; } diff --git a/net/core/dev.c b/net/core/dev.c index 9d4369ece679..c482fe8abf87 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3006,7 +3006,7 @@ static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, } skb_reset_network_header(skb); - if (!skb_get_rxhash(skb)) + if (!skb_get_hash(skb)) goto done; flow_table = rcu_dereference(rxqueue->rps_flow_table); @@ -3151,7 +3151,7 @@ static bool skb_flow_limit(struct sk_buff *skb, unsigned int qlen) rcu_read_lock(); fl = rcu_dereference(sd->flow_limit); if (fl) { - new_flow = skb_get_rxhash(skb) & (fl->num_buckets - 1); + new_flow = skb_get_hash(skb) & (fl->num_buckets - 1); old_flow = fl->history[fl->history_head]; fl->history[fl->history_head] = new_flow; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index d6ef17322500..b324bfa3485c 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -202,12 +202,12 @@ static __always_inline u32 __flow_hash_1word(u32 a) } /* - * __skb_get_rxhash: calculate a flow hash based on src/dst addresses + * __skb_get_hash: calculate a flow hash based on src/dst addresses * and src/dst port numbers. Sets rxhash in skb to non-zero hash value * on success, zero indicates no valid hash. Also, sets l4_rxhash in skb * if hash is a canonical 4-tuple hash over transport ports. */ -void __skb_get_rxhash(struct sk_buff *skb) +void __skb_get_hash(struct sk_buff *skb) { struct flow_keys keys; u32 hash; @@ -234,7 +234,7 @@ void __skb_get_rxhash(struct sk_buff *skb) skb->rxhash = hash; } -EXPORT_SYMBOL(__skb_get_rxhash); +EXPORT_SYMBOL(__skb_get_hash); /* * Returns a Tx hash based on the given packet descriptor a Tx queues' number diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index cc803c63059a..24675f06f4fd 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -963,7 +963,7 @@ static void prb_clear_blk_fill_status(struct packet_ring_buffer *rb) static void prb_fill_rxhash(struct tpacket_kbdq_core *pkc, struct tpacket3_hdr *ppd) { - ppd->hv1.tp_rxhash = skb_get_rxhash(pkc->skb); + ppd->hv1.tp_rxhash = skb_get_hash(pkc->skb); } static void prb_clear_rxhash(struct tpacket_kbdq_core *pkc, @@ -1295,7 +1295,7 @@ static int packet_rcv_fanout(struct sk_buff *skb, struct net_device *dev, if (!skb) return 0; } - skb_get_rxhash(skb); + skb_get_hash(skb); idx = fanout_demux_hash(f, skb, num); break; case PACKET_FANOUT_LB: diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index 7881e2fccbc2..83a6322b7751 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -220,7 +220,7 @@ static u32 flow_get_vlan_tag(const struct sk_buff *skb) static u32 flow_get_rxhash(struct sk_buff *skb) { - return skb_get_rxhash(skb); + return skb_get_hash(skb); } static u32 flow_key_get(struct sk_buff *skb, int key, struct flow_keys *flow) diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c index 382519a5d7f9..9b8c0b0e60d7 100644 --- a/net/sched/em_meta.c +++ b/net/sched/em_meta.c @@ -222,7 +222,7 @@ META_COLLECTOR(int_maclen) META_COLLECTOR(int_rxhash) { - dst->value = skb_get_rxhash(skb); + dst->value = skb_get_hash(skb); } /************************************************************************** diff --git a/net/sched/sch_fq.c b/net/sched/sch_fq.c index f2fb92dd970d..08ef7a42c0e4 100644 --- a/net/sched/sch_fq.c +++ b/net/sched/sch_fq.c @@ -226,7 +226,7 @@ static struct fq_flow *fq_classify(struct sk_buff *skb, struct fq_sched_data *q) /* By forcing low order bit to 1, we make sure to not * collide with a local flow (socket pointers are word aligned) */ - sk = (struct sock *)(skb_get_rxhash(skb) | 1L); + sk = (struct sock *)(skb_get_hash(skb) | 1L); } root = &q->fq_root[hash_32((u32)(long)sk, q->fq_trees_log)]; -- cgit v1.2.3-59-g8ed1b From 7539fadcb8146a5f0db51e80d99c9e724efec7b0 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Sun, 15 Dec 2013 22:12:18 -0800 Subject: net: Add utility functions to clear rxhash In several places 'skb->rxhash = 0' is being done to clear the rxhash value in an skb. This does not clear l4_rxhash which could still be set so that the rxhash wouldn't be recalculated on subsequent call to skb_get_rxhash. This patch adds an explict function to clear all the rxhash related information in the skb properly. skb_clear_hash_if_not_l4 clears the rxhash only if it is not marked as l4_rxhash. Fixed up places where 'skb->rxhash = 0' was being called. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/skbuff.h | 12 ++++++++++++ include/net/dst.h | 5 ++--- net/ipv4/ip_fragment.c | 2 +- net/ipv4/ip_tunnel_core.c | 5 ++--- net/openvswitch/actions.c | 10 +++++----- 5 files changed, 22 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 4725b953e00d..7deb7ad65914 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -712,6 +712,18 @@ static inline __u32 skb_get_hash(struct sk_buff *skb) return skb->rxhash; } +static inline void skb_clear_hash(struct sk_buff *skb) +{ + skb->rxhash = 0; + skb->l4_rxhash = 0; +} + +static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb) +{ + if (!skb->l4_rxhash) + skb_clear_hash(skb); +} + #ifdef NET_SKBUFF_DATA_USES_OFFSET static inline unsigned char *skb_end_pointer(const struct sk_buff *skb) { diff --git a/include/net/dst.h b/include/net/dst.h index 44995c13e941..77eb53fabfb0 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -322,12 +322,11 @@ static inline void __skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev, skb->dev = dev; /* - * Clear rxhash so that we can recalulate the hash for the + * Clear hash so that we can recalulate the hash for the * encapsulated packet, unless we have already determine the hash * over the L4 4-tuple. */ - if (!skb->l4_rxhash) - skb->rxhash = 0; + skb_clear_hash_if_not_l4(skb); skb_set_queue_mapping(skb, 0); skb_scrub_packet(skb, !net_eq(net, dev_net(dev))); } diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 2481993a4970..c10a3ce5cbff 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -704,7 +704,7 @@ struct sk_buff *ip_check_defrag(struct sk_buff *skb, u32 user) memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); if (ip_defrag(skb, user)) return NULL; - skb->rxhash = 0; + skb_clear_hash(skb); } } return skb; diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 42ffbc8d65c6..6156f4ef5e91 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -56,7 +56,7 @@ int iptunnel_xmit(struct rtable *rt, struct sk_buff *skb, skb_scrub_packet(skb, xnet); - skb->rxhash = 0; + skb_clear_hash(skb); skb_dst_set(skb, &rt->dst); memset(IPCB(skb), 0, sizeof(*IPCB(skb))); @@ -107,8 +107,7 @@ int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto) nf_reset(skb); secpath_reset(skb); - if (!skb->l4_rxhash) - skb->rxhash = 0; + skb_clear_hash_if_not_l4(skb); skb_dst_drop(skb); skb->vlan_tci = 0; skb_set_queue_mapping(skb, 0); diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 65cfaa816075..716b7eebfe70 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -165,7 +165,7 @@ static void set_ip_addr(struct sk_buff *skb, struct iphdr *nh, } csum_replace4(&nh->check, *addr, new_addr); - skb->rxhash = 0; + skb_clear_hash(skb); *addr = new_addr; } @@ -199,7 +199,7 @@ static void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto, if (recalculate_csum) update_ipv6_checksum(skb, l4_proto, addr, new_addr); - skb->rxhash = 0; + skb_clear_hash(skb); memcpy(addr, new_addr, sizeof(__be32[4])); } @@ -296,7 +296,7 @@ static void set_tp_port(struct sk_buff *skb, __be16 *port, { inet_proto_csum_replace2(check, skb, *port, new_port, 0); *port = new_port; - skb->rxhash = 0; + skb_clear_hash(skb); } static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port) @@ -310,7 +310,7 @@ static void set_udp_port(struct sk_buff *skb, __be16 *port, __be16 new_port) uh->check = CSUM_MANGLED_0; } else { *port = new_port; - skb->rxhash = 0; + skb_clear_hash(skb); } } @@ -381,7 +381,7 @@ static int set_sctp(struct sk_buff *skb, /* Carry any checksum errors through. */ sh->checksum = old_csum ^ old_correct_csum ^ new_csum; - skb->rxhash = 0; + skb_clear_hash(skb); } return 0; -- cgit v1.2.3-59-g8ed1b From 09323cc479316e046931a2c679932204b36fea6c Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Sun, 15 Dec 2013 22:16:19 -0800 Subject: net: Add function to set the rxhash The function skb_set_rxash was added for drivers to call to set the rxhash in an skb. The type of hash is also specified as a parameter (L2, L3, L4, or unknown type). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/skbuff.h | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 7deb7ad65914..99846956dff9 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -703,6 +703,46 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, unsigned int to, struct ts_config *config, struct ts_state *state); +/* + * Packet hash types specify the type of hash in skb_set_hash. + * + * Hash types refer to the protocol layer addresses which are used to + * construct a packet's hash. The hashes are used to differentiate or identify + * flows of the protocol layer for the hash type. Hash types are either + * layer-2 (L2), layer-3 (L3), or layer-4 (L4). + * + * Properties of hashes: + * + * 1) Two packets in different flows have different hash values + * 2) Two packets in the same flow should have the same hash value + * + * A hash at a higher layer is considered to be more specific. A driver should + * set the most specific hash possible. + * + * A driver cannot indicate a more specific hash than the layer at which a hash + * was computed. For instance an L3 hash cannot be set as an L4 hash. + * + * A driver may indicate a hash level which is less specific than the + * actual layer the hash was computed on. For instance, a hash computed + * at L4 may be considered an L3 hash. This should only be done if the + * driver can't unambiguously determine that the HW computed the hash at + * the higher layer. Note that the "should" in the second property above + * permits this. + */ +enum pkt_hash_types { + PKT_HASH_TYPE_NONE, /* Undefined type */ + PKT_HASH_TYPE_L2, /* Input: src_MAC, dest_MAC */ + PKT_HASH_TYPE_L3, /* Input: src_IP, dst_IP */ + PKT_HASH_TYPE_L4, /* Input: src_IP, dst_IP, src_port, dst_port */ +}; + +static inline void +skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type) +{ + skb->l4_rxhash = (type == PKT_HASH_TYPE_L4); + skb->rxhash = hash; +} + void __skb_get_hash(struct sk_buff *skb); static inline __u32 skb_get_hash(struct sk_buff *skb) { -- cgit v1.2.3-59-g8ed1b From 3df7a74e797aa2d8be9b7c649cfd56a8517dcf6e Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Sun, 15 Dec 2013 22:16:29 -0800 Subject: net: Add utility function to copy skb hash Adds skb_copy_hash to copy rxhash and l4_rxhash from one skb to another. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/skbuff.h | 6 ++++++ net/core/skbuff.c | 3 +-- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 99846956dff9..06bedeb0d49e 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -764,6 +764,12 @@ static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb) skb_clear_hash(skb); } +static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from) +{ + to->rxhash = from->rxhash; + to->l4_rxhash = from->l4_rxhash; +}; + #ifdef NET_SKBUFF_DATA_USES_OFFSET static inline unsigned char *skb_end_pointer(const struct sk_buff *skb) { diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 06e72d3cdf60..2b6b863f51f2 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -712,9 +712,8 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->inner_network_header = old->inner_network_header; new->inner_mac_header = old->inner_mac_header; skb_dst_copy(new, old); - new->rxhash = old->rxhash; + skb_copy_hash(new, old); new->ooo_okay = old->ooo_okay; - new->l4_rxhash = old->l4_rxhash; new->no_fcs = old->no_fcs; new->encapsulation = old->encapsulation; #ifdef CONFIG_XFRM -- cgit v1.2.3-59-g8ed1b From 157e876ffe0b28821a0d82d8ac944fe7363bbe87 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 17 Dec 2013 16:43:39 -0700 Subject: PCI: Add pci_wait_for_pending() (refactor pci_wait_for_pending_transaction()) We currently have two instance of this loop which waits for a pending bit to clear in a status dword. Generalize the function for future users. Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 54 ++++++++++++++++++++++++++++++----------------------- include/linux/pci.h | 1 + 2 files changed, 32 insertions(+), 23 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 33120d156668..bb257b975a8f 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -430,6 +430,32 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res) return best; } +/** + * pci_wait_for_pending - wait for @mask bit(s) to clear in status word @pos + * @dev: the PCI device to operate on + * @pos: config space offset of status word + * @mask: mask of bit(s) to care about in status word + * + * Return 1 when mask bit(s) in status word clear, 0 otherwise. + */ +int pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask) +{ + int i; + + /* Wait for Transaction Pending bit clean */ + for (i = 0; i < 4; i++) { + u16 status; + if (i) + msleep((1 << (i - 1)) * 100); + + pci_read_config_word(dev, pos, &status); + if (!(status & mask)) + return 1; + } + + return 0; +} + /** * pci_restore_bars - restore a devices BAR values (e.g. after wake-up) * @dev: PCI device to have its BARs restored @@ -3204,20 +3230,10 @@ EXPORT_SYMBOL(pci_set_dma_seg_boundary); */ int pci_wait_for_pending_transaction(struct pci_dev *dev) { - int i; - u16 status; - - /* Wait for Transaction Pending bit clean */ - for (i = 0; i < 4; i++) { - if (i) - msleep((1 << (i - 1)) * 100); - - pcie_capability_read_word(dev, PCI_EXP_DEVSTA, &status); - if (!(status & PCI_EXP_DEVSTA_TRPND)) - return 1; - } + if (!pci_is_pcie(dev)) + return 1; - return 0; + return pci_wait_for_pending(dev, PCI_EXP_DEVSTA, PCI_EXP_DEVSTA_TRPND); } EXPORT_SYMBOL(pci_wait_for_pending_transaction); @@ -3244,10 +3260,8 @@ static int pcie_flr(struct pci_dev *dev, int probe) static int pci_af_flr(struct pci_dev *dev, int probe) { - int i; int pos; u8 cap; - u8 status; pos = pci_find_capability(dev, PCI_CAP_ID_AF); if (!pos) @@ -3261,14 +3275,8 @@ static int pci_af_flr(struct pci_dev *dev, int probe) return 0; /* Wait for Transaction Pending bit clean */ - for (i = 0; i < 4; i++) { - if (i) - msleep((1 << (i - 1)) * 100); - - pci_read_config_byte(dev, pos + PCI_AF_STATUS, &status); - if (!(status & PCI_AF_STATUS_TP)) - goto clear; - } + if (pci_wait_for_pending(dev, PCI_AF_STATUS, PCI_AF_STATUS_TP)) + goto clear; dev_err(&dev->dev, "transaction is not cleared; " "proceeding with reset anyway\n"); diff --git a/include/linux/pci.h b/include/linux/pci.h index 1084a15175e0..211ce43ba483 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -938,6 +938,7 @@ bool pci_check_and_unmask_intx(struct pci_dev *dev); void pci_msi_off(struct pci_dev *dev); int pci_set_dma_max_seg_size(struct pci_dev *dev, unsigned int size); int pci_set_dma_seg_boundary(struct pci_dev *dev, unsigned long mask); +int pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask); int pci_wait_for_pending_transaction(struct pci_dev *dev); int pcix_get_max_mmrbc(struct pci_dev *dev); int pcix_get_mmrbc(struct pci_dev *dev); -- cgit v1.2.3-59-g8ed1b From fd0f7f73ca96bb0f8723b5e59759ad43bab88954 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 17 Dec 2013 16:43:45 -0700 Subject: PCI: Add support for save/restore of extended capabilities Current save/restore is specific to standard capabilities. Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.c | 43 +++++++++++++++++++++++++++++++++++-------- include/linux/pci.h | 9 ++++++++- 2 files changed, 43 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index bb257b975a8f..8f2be7ec705c 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -861,18 +861,28 @@ EXPORT_SYMBOL(pci_choose_state); #define PCI_EXP_SAVE_REGS 7 -static struct pci_cap_saved_state *pci_find_saved_cap( - struct pci_dev *pci_dev, char cap) +static struct pci_cap_saved_state *_pci_find_saved_cap(struct pci_dev *pci_dev, + u16 cap, bool extended) { struct pci_cap_saved_state *tmp; hlist_for_each_entry(tmp, &pci_dev->saved_cap_space, next) { - if (tmp->cap.cap_nr == cap) + if (tmp->cap.cap_extended == extended && tmp->cap.cap_nr == cap) return tmp; } return NULL; } +struct pci_cap_saved_state *pci_find_saved_cap(struct pci_dev *dev, char cap) +{ + return _pci_find_saved_cap(dev, cap, false); +} + +struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev, u16 cap) +{ + return _pci_find_saved_cap(dev, cap, true); +} + static int pci_save_pcie_state(struct pci_dev *dev) { int i = 0; @@ -1113,7 +1123,7 @@ int pci_load_saved_state(struct pci_dev *dev, struct pci_saved_state *state) while (cap->size) { struct pci_cap_saved_state *tmp; - tmp = pci_find_saved_cap(dev, cap->cap_nr); + tmp = _pci_find_saved_cap(dev, cap->cap_nr, cap->cap_extended); if (!tmp || tmp->cap.size != cap->size) return -EINVAL; @@ -2047,18 +2057,24 @@ static void pci_add_saved_cap(struct pci_dev *pci_dev, } /** - * pci_add_cap_save_buffer - allocate buffer for saving given capability registers + * _pci_add_cap_save_buffer - allocate buffer for saving given + * capability registers * @dev: the PCI device * @cap: the capability to allocate the buffer for + * @extended: Standard or Extended capability ID * @size: requested size of the buffer */ -static int pci_add_cap_save_buffer( - struct pci_dev *dev, char cap, unsigned int size) +static int _pci_add_cap_save_buffer(struct pci_dev *dev, u16 cap, + bool extended, unsigned int size) { int pos; struct pci_cap_saved_state *save_state; - pos = pci_find_capability(dev, cap); + if (extended) + pos = pci_find_ext_capability(dev, cap); + else + pos = pci_find_capability(dev, cap); + if (pos <= 0) return 0; @@ -2067,12 +2083,23 @@ static int pci_add_cap_save_buffer( return -ENOMEM; save_state->cap.cap_nr = cap; + save_state->cap.cap_extended = extended; save_state->cap.size = size; pci_add_saved_cap(dev, save_state); return 0; } +int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size) +{ + return _pci_add_cap_save_buffer(dev, cap, false, size); +} + +int pci_add_ext_cap_save_buffer(struct pci_dev *dev, u16 cap, unsigned int size) +{ + return _pci_add_cap_save_buffer(dev, cap, true, size); +} + /** * pci_allocate_cap_save_buffers - allocate buffers for saving capabilities * @dev: the PCI device diff --git a/include/linux/pci.h b/include/linux/pci.h index 211ce43ba483..1bb75b0c4c6f 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -224,7 +224,8 @@ enum pci_bus_speed { }; struct pci_cap_saved_data { - char cap_nr; + u16 cap_nr; + bool cap_extended; unsigned int size; u32 data[0]; }; @@ -977,6 +978,12 @@ struct pci_saved_state *pci_store_saved_state(struct pci_dev *dev); int pci_load_saved_state(struct pci_dev *dev, struct pci_saved_state *state); int pci_load_and_free_saved_state(struct pci_dev *dev, struct pci_saved_state **state); +struct pci_cap_saved_state *pci_find_saved_cap(struct pci_dev *dev, char cap); +struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev, + u16 cap); +int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size); +int pci_add_ext_cap_save_buffer(struct pci_dev *dev, + u16 cap, unsigned int size); int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state); int pci_set_power_state(struct pci_dev *dev, pci_power_t state); pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state); -- cgit v1.2.3-59-g8ed1b From 425c1b223dac456d00a61fd6b451b6d1cf00d065 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Tue, 17 Dec 2013 16:43:51 -0700 Subject: PCI: Add Virtual Channel to save/restore support While we don't really have any infrastructure for making use of VC support, the system BIOS can configure the topology to non-default VC values prior to boot. This may be due to silicon bugs, desire to reserve traffic classes, or perhaps just BIOS bugs. When we reset devices, the VC configuration may return to default values, which can be incompatible with devices upstream. For instance, Nvidia GRID cards provide a PCIe switch and some number of GPUs, all supporting VC. The power-on default for VC is to support TC0-7 across VC0, however some platforms will only enable TC0/VC0 mapping across the topology. When we do a secondary bus reset on the downstream switch port, the GPU is reset to a TC0-7/VC0 mapping while the opposite end of the link only enables TC0/VC0. If the GPU attempts to use TC1-7, it fails. This patch attempts to provide complete support for VC save/restore, even beyond the minimally required use case above. This includes save/restore and reload of the arbitration table, save/restore and reload of the port arbitration tables, and re-enabling of the channels for VC, VC9, and MFVC capabilities. Signed-off-by: Alex Williamson Signed-off-by: Bjorn Helgaas --- drivers/pci/Makefile | 2 +- drivers/pci/pci.c | 5 + drivers/pci/vc.c | 434 ++++++++++++++++++++++++++++++++++++++++++ include/linux/pci.h | 5 + include/uapi/linux/pci_regs.h | 25 ++- 5 files changed, 466 insertions(+), 5 deletions(-) create mode 100644 drivers/pci/vc.c (limited to 'include/linux') diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 6ebf5bf8e7a7..17d2b07ee67c 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -4,7 +4,7 @@ obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \ pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \ - irq.o vpd.o setup-bus.o + irq.o vpd.o setup-bus.o vc.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_SYSFS) += slot.o diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8f2be7ec705c..508e560b7d2a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -984,6 +984,8 @@ pci_save_state(struct pci_dev *dev) return i; if ((i = pci_save_pcix_state(dev)) != 0) return i; + if ((i = pci_save_vc_state(dev)) != 0) + return i; return 0; } @@ -1046,6 +1048,7 @@ void pci_restore_state(struct pci_dev *dev) /* PCI Express register must be restored first */ pci_restore_pcie_state(dev); pci_restore_ats_state(dev); + pci_restore_vc_state(dev); pci_restore_config_space(dev); @@ -2118,6 +2121,8 @@ void pci_allocate_cap_save_buffers(struct pci_dev *dev) if (error) dev_err(&dev->dev, "unable to preallocate PCI-X save buffer\n"); + + pci_allocate_vc_save_buffers(dev); } void pci_free_cap_save_buffers(struct pci_dev *dev) diff --git a/drivers/pci/vc.c b/drivers/pci/vc.c new file mode 100644 index 000000000000..c10567e4f14f --- /dev/null +++ b/drivers/pci/vc.c @@ -0,0 +1,434 @@ +/* + * PCI Virtual Channel support + * + * Copyright (C) 2013 Red Hat, Inc. All rights reserved. + * Author: Alex Williamson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +/** + * pci_vc_save_restore_dwords - Save or restore a series of dwords + * @dev: device + * @pos: starting config space position + * @buf: buffer to save to or restore from + * @dwords: number of dwords to save/restore + * @save: whether to save or restore + */ +static void pci_vc_save_restore_dwords(struct pci_dev *dev, int pos, + u32 *buf, int dwords, bool save) +{ + int i; + + for (i = 0; i < dwords; i++, buf++) { + if (save) + pci_read_config_dword(dev, pos + (i * 4), buf); + else + pci_write_config_dword(dev, pos + (i * 4), *buf); + } +} + +/** + * pci_vc_load_arb_table - load and wait for VC arbitration table + * @dev: device + * @pos: starting position of VC capability (VC/VC9/MFVC) + * + * Set Load VC Arbitration Table bit requesting hardware to apply the VC + * Arbitration Table (previously loaded). When the VC Arbitration Table + * Status clears, hardware has latched the table into VC arbitration logic. + */ +static void pci_vc_load_arb_table(struct pci_dev *dev, int pos) +{ + u16 ctrl; + + pci_read_config_word(dev, pos + PCI_VC_PORT_CTRL, &ctrl); + pci_write_config_word(dev, pos + PCI_VC_PORT_CTRL, + ctrl | PCI_VC_PORT_CTRL_LOAD_TABLE); + if (pci_wait_for_pending(dev, pos + PCI_VC_PORT_STATUS, + PCI_VC_PORT_STATUS_TABLE)) + return; + + dev_err(&dev->dev, "VC arbitration table failed to load\n"); +} + +/** + * pci_vc_load_port_arb_table - Load and wait for VC port arbitration table + * @dev: device + * @pos: starting position of VC capability (VC/VC9/MFVC) + * @res: VC resource number, ie. VCn (0-7) + * + * Set Load Port Arbitration Table bit requesting hardware to apply the Port + * Arbitration Table (previously loaded). When the Port Arbitration Table + * Status clears, hardware has latched the table into port arbitration logic. + */ +static void pci_vc_load_port_arb_table(struct pci_dev *dev, int pos, int res) +{ + int ctrl_pos, status_pos; + u32 ctrl; + + ctrl_pos = pos + PCI_VC_RES_CTRL + (res * PCI_CAP_VC_PER_VC_SIZEOF); + status_pos = pos + PCI_VC_RES_STATUS + (res * PCI_CAP_VC_PER_VC_SIZEOF); + + pci_read_config_dword(dev, ctrl_pos, &ctrl); + pci_write_config_dword(dev, ctrl_pos, + ctrl | PCI_VC_RES_CTRL_LOAD_TABLE); + + if (pci_wait_for_pending(dev, status_pos, PCI_VC_RES_STATUS_TABLE)) + return; + + dev_err(&dev->dev, "VC%d port arbitration table failed to load\n", res); +} + +/** + * pci_vc_enable - Enable virtual channel + * @dev: device + * @pos: starting position of VC capability (VC/VC9/MFVC) + * @res: VC res number, ie. VCn (0-7) + * + * A VC is enabled by setting the enable bit in matching resource control + * registers on both sides of a link. We therefore need to find the opposite + * end of the link. To keep this simple we enable from the downstream device. + * RC devices do not have an upstream device, nor does it seem that VC9 do + * (spec is unclear). Once we find the upstream device, match the VC ID to + * get the correct resource, disable and enable on both ends. + */ +static void pci_vc_enable(struct pci_dev *dev, int pos, int res) +{ + int ctrl_pos, status_pos, id, pos2, evcc, i, ctrl_pos2, status_pos2; + u32 ctrl, header, reg1, ctrl2; + struct pci_dev *link = NULL; + + /* Enable VCs from the downstream device */ + if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT || + pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) + return; + + ctrl_pos = pos + PCI_VC_RES_CTRL + (res * PCI_CAP_VC_PER_VC_SIZEOF); + status_pos = pos + PCI_VC_RES_STATUS + (res * PCI_CAP_VC_PER_VC_SIZEOF); + + pci_read_config_dword(dev, ctrl_pos, &ctrl); + id = ctrl & PCI_VC_RES_CTRL_ID; + + pci_read_config_dword(dev, pos, &header); + + /* If there is no opposite end of the link, skip to enable */ + if (PCI_EXT_CAP_ID(header) == PCI_EXT_CAP_ID_VC9 || + pci_is_root_bus(dev->bus)) + goto enable; + + pos2 = pci_find_ext_capability(dev->bus->self, PCI_EXT_CAP_ID_VC); + if (!pos2) + goto enable; + + pci_read_config_dword(dev->bus->self, pos2 + PCI_VC_PORT_REG1, ®1); + evcc = reg1 & PCI_VC_REG1_EVCC; + + /* VC0 is hardwired enabled, so we can start with 1 */ + for (i = 1; i < evcc + 1; i++) { + ctrl_pos2 = pos2 + PCI_VC_RES_CTRL + + (i * PCI_CAP_VC_PER_VC_SIZEOF); + status_pos2 = pos2 + PCI_VC_RES_STATUS + + (i * PCI_CAP_VC_PER_VC_SIZEOF); + pci_read_config_dword(dev->bus->self, ctrl_pos2, &ctrl2); + if ((ctrl2 & PCI_VC_RES_CTRL_ID) == id) { + link = dev->bus->self; + break; + } + } + + if (!link) + goto enable; + + /* Disable if enabled */ + if (ctrl2 & PCI_VC_RES_CTRL_ENABLE) { + ctrl2 &= ~PCI_VC_RES_CTRL_ENABLE; + pci_write_config_dword(link, ctrl_pos2, ctrl2); + } + + /* Enable on both ends */ + ctrl2 |= PCI_VC_RES_CTRL_ENABLE; + pci_write_config_dword(link, ctrl_pos2, ctrl2); +enable: + ctrl |= PCI_VC_RES_CTRL_ENABLE; + pci_write_config_dword(dev, ctrl_pos, ctrl); + + if (!pci_wait_for_pending(dev, status_pos, PCI_VC_RES_STATUS_NEGO)) + dev_err(&dev->dev, "VC%d negotiation stuck pending\n", id); + + if (link && !pci_wait_for_pending(link, status_pos2, + PCI_VC_RES_STATUS_NEGO)) + dev_err(&link->dev, "VC%d negotiation stuck pending\n", id); +} + +/** + * pci_vc_do_save_buffer - Size, save, or restore VC state + * @dev: device + * @pos: starting position of VC capability (VC/VC9/MFVC) + * @save_state: buffer for save/restore + * @name: for error message + * @save: if provided a buffer, this indicates what to do with it + * + * Walking Virtual Channel config space to size, save, or restore it + * is complicated, so we do it all from one function to reduce code and + * guarantee ordering matches in the buffer. When called with NULL + * @save_state, return the size of the necessary save buffer. When called + * with a non-NULL @save_state, @save determines whether we save to the + * buffer or restore from it. + */ +static int pci_vc_do_save_buffer(struct pci_dev *dev, int pos, + struct pci_cap_saved_state *save_state, + bool save) +{ + u32 reg1; + char evcc, lpevcc, parb_size; + int i, len = 0; + u8 *buf = save_state ? (u8 *)save_state->cap.data : NULL; + + /* Sanity check buffer size for save/restore */ + if (buf && save_state->cap.size != + pci_vc_do_save_buffer(dev, pos, NULL, save)) { + dev_err(&dev->dev, + "VC save buffer size does not match @0x%x\n", pos); + return -ENOMEM; + } + + pci_read_config_dword(dev, pos + PCI_VC_PORT_REG1, ®1); + /* Extended VC Count (not counting VC0) */ + evcc = reg1 & PCI_VC_REG1_EVCC; + /* Low Priority Extended VC Count (not counting VC0) */ + lpevcc = (reg1 & PCI_VC_REG1_LPEVCC) >> 4; + /* Port Arbitration Table Entry Size (bits) */ + parb_size = 1 << ((reg1 & PCI_VC_REG1_ARB_SIZE) >> 10); + + /* + * Port VC Control Register contains VC Arbitration Select, which + * cannot be modified when more than one LPVC is in operation. We + * therefore save/restore it first, as only VC0 should be enabled + * after device reset. + */ + if (buf) { + if (save) + pci_read_config_word(dev, pos + PCI_VC_PORT_CTRL, + (u16 *)buf); + else + pci_write_config_word(dev, pos + PCI_VC_PORT_CTRL, + *(u16 *)buf); + buf += 2; + } + len += 2; + + /* + * If we have any Low Priority VCs and a VC Arbitration Table Offset + * in Port VC Capability Register 2 then save/restore it next. + */ + if (lpevcc) { + u32 reg2; + int vcarb_offset; + + pci_read_config_dword(dev, pos + PCI_VC_PORT_REG2, ®2); + vcarb_offset = ((reg2 & PCI_VC_REG2_ARB_OFF) >> 24) * 16; + + if (vcarb_offset) { + int size, vcarb_phases = 0; + + if (reg2 & PCI_VC_REG2_128_PHASE) + vcarb_phases = 128; + else if (reg2 & PCI_VC_REG2_64_PHASE) + vcarb_phases = 64; + else if (reg2 & PCI_VC_REG2_32_PHASE) + vcarb_phases = 32; + + /* Fixed 4 bits per phase per lpevcc (plus VC0) */ + size = ((lpevcc + 1) * vcarb_phases * 4) / 8; + + if (size && buf) { + pci_vc_save_restore_dwords(dev, + pos + vcarb_offset, + (u32 *)buf, + size / 4, save); + /* + * On restore, we need to signal hardware to + * re-load the VC Arbitration Table. + */ + if (!save) + pci_vc_load_arb_table(dev, pos); + + buf += size; + } + len += size; + } + } + + /* + * In addition to each VC Resource Control Register, we may have a + * Port Arbitration Table attached to each VC. The Port Arbitration + * Table Offset in each VC Resource Capability Register tells us if + * it exists. The entry size is global from the Port VC Capability + * Register1 above. The number of phases is determined per VC. + */ + for (i = 0; i < evcc + 1; i++) { + u32 cap; + int parb_offset; + + pci_read_config_dword(dev, pos + PCI_VC_RES_CAP + + (i * PCI_CAP_VC_PER_VC_SIZEOF), &cap); + parb_offset = ((cap & PCI_VC_RES_CAP_ARB_OFF) >> 24) * 16; + if (parb_offset) { + int size, parb_phases = 0; + + if (cap & PCI_VC_RES_CAP_256_PHASE) + parb_phases = 256; + else if (cap & (PCI_VC_RES_CAP_128_PHASE | + PCI_VC_RES_CAP_128_PHASE_TB)) + parb_phases = 128; + else if (cap & PCI_VC_RES_CAP_64_PHASE) + parb_phases = 64; + else if (cap & PCI_VC_RES_CAP_32_PHASE) + parb_phases = 32; + + size = (parb_size * parb_phases) / 8; + + if (size && buf) { + pci_vc_save_restore_dwords(dev, + pos + parb_offset, + (u32 *)buf, + size / 4, save); + buf += size; + } + len += size; + } + + /* VC Resource Control Register */ + if (buf) { + int ctrl_pos = pos + PCI_VC_RES_CTRL + + (i * PCI_CAP_VC_PER_VC_SIZEOF); + if (save) + pci_read_config_dword(dev, ctrl_pos, + (u32 *)buf); + else { + u32 tmp, ctrl = *(u32 *)buf; + /* + * For an FLR case, the VC config may remain. + * Preserve enable bit, restore the rest. + */ + pci_read_config_dword(dev, ctrl_pos, &tmp); + tmp &= PCI_VC_RES_CTRL_ENABLE; + tmp |= ctrl & ~PCI_VC_RES_CTRL_ENABLE; + pci_write_config_dword(dev, ctrl_pos, tmp); + /* Load port arbitration table if used */ + if (ctrl & PCI_VC_RES_CTRL_ARB_SELECT) + pci_vc_load_port_arb_table(dev, pos, i); + /* Re-enable if needed */ + if ((ctrl ^ tmp) & PCI_VC_RES_CTRL_ENABLE) + pci_vc_enable(dev, pos, i); + } + buf += 4; + } + len += 4; + } + + return buf ? 0 : len; +} + +static struct { + u16 id; + const char *name; +} vc_caps[] = { { PCI_EXT_CAP_ID_MFVC, "MFVC" }, + { PCI_EXT_CAP_ID_VC, "VC" }, + { PCI_EXT_CAP_ID_VC9, "VC9" } }; + +/** + * pci_save_vc_state - Save VC state to pre-allocate save buffer + * @dev: device + * + * For each type of VC capability, VC/VC9/MFVC, find the capability and + * save it to the pre-allocated save buffer. + */ +int pci_save_vc_state(struct pci_dev *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vc_caps); i++) { + int pos, ret; + struct pci_cap_saved_state *save_state; + + pos = pci_find_ext_capability(dev, vc_caps[i].id); + if (!pos) + continue; + + save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id); + if (!save_state) { + dev_err(&dev->dev, "%s buffer not found in %s\n", + vc_caps[i].name, __func__); + return -ENOMEM; + } + + ret = pci_vc_do_save_buffer(dev, pos, save_state, true); + if (ret) { + dev_err(&dev->dev, "%s save unsuccessful %s\n", + vc_caps[i].name, __func__); + return ret; + } + } + + return 0; +} + +/** + * pci_restore_vc_state - Restore VC state from save buffer + * @dev: device + * + * For each type of VC capability, VC/VC9/MFVC, find the capability and + * restore it from the previously saved buffer. + */ +void pci_restore_vc_state(struct pci_dev *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vc_caps); i++) { + int pos; + struct pci_cap_saved_state *save_state; + + pos = pci_find_ext_capability(dev, vc_caps[i].id); + save_state = pci_find_saved_ext_cap(dev, vc_caps[i].id); + if (!save_state || !pos) + continue; + + pci_vc_do_save_buffer(dev, pos, save_state, false); + } +} + +/** + * pci_allocate_vc_save_buffers - Allocate save buffers for VC caps + * @dev: device + * + * For each type of VC capability, VC/VC9/MFVC, find the capability, size + * it, and allocate a buffer for save/restore. + */ + +void pci_allocate_vc_save_buffers(struct pci_dev *dev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(vc_caps); i++) { + int len, pos = pci_find_ext_capability(dev, vc_caps[i].id); + + if (!pos) + continue; + + len = pci_vc_do_save_buffer(dev, pos, NULL, false); + if (pci_add_ext_cap_save_buffer(dev, vc_caps[i].id, len)) + dev_err(&dev->dev, + "unable to preallocate %s save buffer\n", + vc_caps[i].name); + } +} diff --git a/include/linux/pci.h b/include/linux/pci.h index 1bb75b0c4c6f..ef34ad76532c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1005,6 +1005,11 @@ static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, return __pci_enable_wake(dev, state, false, enable); } +/* PCI Virtual Channel */ +int pci_save_vc_state(struct pci_dev *dev); +void pci_restore_vc_state(struct pci_dev *dev); +void pci_allocate_vc_save_buffers(struct pci_dev *dev); + #define PCI_EXP_IDO_REQUEST (1<<0) #define PCI_EXP_IDO_COMPLETION (1<<1) void pci_enable_ido(struct pci_dev *dev, unsigned long type); diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index 4a98e85438a7..5eefacd93e18 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -678,16 +678,33 @@ /* Virtual Channel */ #define PCI_VC_PORT_REG1 4 -#define PCI_VC_REG1_EVCC 0x7 /* extended VC count */ +#define PCI_VC_REG1_EVCC 0x00000007 /* extended VC count */ +#define PCI_VC_REG1_LPEVCC 0x00000070 /* low prio extended VC count */ +#define PCI_VC_REG1_ARB_SIZE 0x00000c00 #define PCI_VC_PORT_REG2 8 -#define PCI_VC_REG2_32_PHASE 0x2 -#define PCI_VC_REG2_64_PHASE 0x4 -#define PCI_VC_REG2_128_PHASE 0x8 +#define PCI_VC_REG2_32_PHASE 0x00000002 +#define PCI_VC_REG2_64_PHASE 0x00000004 +#define PCI_VC_REG2_128_PHASE 0x00000008 +#define PCI_VC_REG2_ARB_OFF 0xff000000 #define PCI_VC_PORT_CTRL 12 +#define PCI_VC_PORT_CTRL_LOAD_TABLE 0x00000001 #define PCI_VC_PORT_STATUS 14 +#define PCI_VC_PORT_STATUS_TABLE 0x00000001 #define PCI_VC_RES_CAP 16 +#define PCI_VC_RES_CAP_32_PHASE 0x00000002 +#define PCI_VC_RES_CAP_64_PHASE 0x00000004 +#define PCI_VC_RES_CAP_128_PHASE 0x00000008 +#define PCI_VC_RES_CAP_128_PHASE_TB 0x00000010 +#define PCI_VC_RES_CAP_256_PHASE 0x00000020 +#define PCI_VC_RES_CAP_ARB_OFF 0xff000000 #define PCI_VC_RES_CTRL 20 +#define PCI_VC_RES_CTRL_LOAD_TABLE 0x00010000 +#define PCI_VC_RES_CTRL_ARB_SELECT 0x000e0000 +#define PCI_VC_RES_CTRL_ID 0x07000000 +#define PCI_VC_RES_CTRL_ENABLE 0x80000000 #define PCI_VC_RES_STATUS 26 +#define PCI_VC_RES_STATUS_TABLE 0x00000001 +#define PCI_VC_RES_STATUS_NEGO 0x00000002 #define PCI_CAP_VC_BASE_SIZEOF 0x10 #define PCI_CAP_VC_PER_VC_SIZEOF 0x0C -- cgit v1.2.3-59-g8ed1b From 46eeb2c144956e88197439b5ee5cf221a91b0a81 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 16 Dec 2013 15:57:39 +0000 Subject: video/fb: Propagate error code from failing to unregister conflicting fb If we fail to remove a conflicting fb driver, we need to abort the loading of the second driver to avoid likely kernel panics. Signed-off-by: Chris Wilson Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: linux-fbdev@vger.kernel.org Cc: dri-devel@lists.freedesktop.org Reviewed-by: Jani Nikula Signed-off-by: Dave Airlie --- drivers/video/fbmem.c | 31 +++++++++++++++++++++---------- include/linux/fb.h | 4 ++-- 2 files changed, 23 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 010d19105ebc..e296967a3abb 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -1577,10 +1577,10 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena, static int do_unregister_framebuffer(struct fb_info *fb_info); #define VGA_FB_PHYS 0xA0000 -static void do_remove_conflicting_framebuffers(struct apertures_struct *a, - const char *name, bool primary) +static int do_remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary) { - int i; + int i, ret; /* check all firmware fbs and kick off if the base addr overlaps */ for (i = 0 ; i < FB_MAX; i++) { @@ -1599,22 +1599,29 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a, printk(KERN_INFO "fb: conflicting fb hw usage " "%s vs %s - removing generic driver\n", name, registered_fb[i]->fix.id); - do_unregister_framebuffer(registered_fb[i]); + ret = do_unregister_framebuffer(registered_fb[i]); + if (ret) + return ret; } } + + return 0; } static int do_register_framebuffer(struct fb_info *fb_info) { - int i; + int i, ret; struct fb_event event; struct fb_videomode mode; if (fb_check_foreignness(fb_info)) return -ENOSYS; - do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id, - fb_is_primary_device(fb_info)); + ret = do_remove_conflicting_framebuffers(fb_info->apertures, + fb_info->fix.id, + fb_is_primary_device(fb_info)); + if (ret) + return ret; if (num_registered_fb == FB_MAX) return -ENXIO; @@ -1739,12 +1746,16 @@ int unlink_framebuffer(struct fb_info *fb_info) } EXPORT_SYMBOL(unlink_framebuffer); -void remove_conflicting_framebuffers(struct apertures_struct *a, - const char *name, bool primary) +int remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary) { + int ret; + mutex_lock(®istration_lock); - do_remove_conflicting_framebuffers(a, name, primary); + ret = do_remove_conflicting_framebuffers(a, name, primary); mutex_unlock(®istration_lock); + + return ret; } EXPORT_SYMBOL(remove_conflicting_framebuffers); diff --git a/include/linux/fb.h b/include/linux/fb.h index 70c4836e4a9f..fe6ac956550e 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -613,8 +613,8 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf, extern int register_framebuffer(struct fb_info *fb_info); extern int unregister_framebuffer(struct fb_info *fb_info); extern int unlink_framebuffer(struct fb_info *fb_info); -extern void remove_conflicting_framebuffers(struct apertures_struct *a, - const char *name, bool primary); +extern int remove_conflicting_framebuffers(struct apertures_struct *a, + const char *name, bool primary); extern int fb_prepare_logo(struct fb_info *fb_info, int rotate); extern int fb_show_logo(struct fb_info *fb_info, int rotate); extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size); -- cgit v1.2.3-59-g8ed1b From e1168c2cc4a5a5e495a53e067a6be6b4f29abfe0 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 22 Nov 2013 18:14:38 -0800 Subject: slab.h: remove duplicate kmalloc declaration and fix kernel-doc warnings Fix kernel-doc warning for duplicate definition of 'kmalloc': Documentation/DocBook/kernel-api.xml:9483: element refentry: validity error : ID API-kmalloc already defined Also combine the kernel-doc info from the 2 kmalloc definitions into one block and remove the "see kcalloc" comment since kmalloc now contains the @flags info. Signed-off-by: Randy Dunlap Acked-by: Christoph Lameter Signed-off-by: Pekka Enberg --- include/linux/slab.h | 102 +++++++++++++++++++++++---------------------------- 1 file changed, 46 insertions(+), 56 deletions(-) (limited to 'include/linux') diff --git a/include/linux/slab.h b/include/linux/slab.h index c2bba248fa63..1e2f4fe12773 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -388,10 +388,55 @@ static __always_inline void *kmalloc_large(size_t size, gfp_t flags) /** * kmalloc - allocate memory * @size: how many bytes of memory are required. - * @flags: the type of memory to allocate (see kcalloc). + * @flags: the type of memory to allocate. * * kmalloc is the normal method of allocating memory * for objects smaller than page size in the kernel. + * + * The @flags argument may be one of: + * + * %GFP_USER - Allocate memory on behalf of user. May sleep. + * + * %GFP_KERNEL - Allocate normal kernel ram. May sleep. + * + * %GFP_ATOMIC - Allocation will not sleep. May use emergency pools. + * For example, use this inside interrupt handlers. + * + * %GFP_HIGHUSER - Allocate pages from high memory. + * + * %GFP_NOIO - Do not do any I/O at all while trying to get memory. + * + * %GFP_NOFS - Do not make any fs calls while trying to get memory. + * + * %GFP_NOWAIT - Allocation will not sleep. + * + * %GFP_THISNODE - Allocate node-local memory only. + * + * %GFP_DMA - Allocation suitable for DMA. + * Should only be used for kmalloc() caches. Otherwise, use a + * slab created with SLAB_DMA. + * + * Also it is possible to set different flags by OR'ing + * in one or more of the following additional @flags: + * + * %__GFP_COLD - Request cache-cold pages instead of + * trying to return cache-warm pages. + * + * %__GFP_HIGH - This allocation has high priority and may use emergency pools. + * + * %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail + * (think twice before using). + * + * %__GFP_NORETRY - If memory is not immediately available, + * then give up at once. + * + * %__GFP_NOWARN - If allocation fails, don't issue any warnings. + * + * %__GFP_REPEAT - If allocation fails initially, try once more before failing. + * + * There are other flags available as well, but these are not intended + * for general use, and so are not documented here. For a full list of + * potential flags, always refer to linux/gfp.h. */ static __always_inline void *kmalloc(size_t size, gfp_t flags) { @@ -501,61 +546,6 @@ struct seq_file; int cache_show(struct kmem_cache *s, struct seq_file *m); void print_slabinfo_header(struct seq_file *m); -/** - * kmalloc - allocate memory - * @size: how many bytes of memory are required. - * @flags: the type of memory to allocate. - * - * The @flags argument may be one of: - * - * %GFP_USER - Allocate memory on behalf of user. May sleep. - * - * %GFP_KERNEL - Allocate normal kernel ram. May sleep. - * - * %GFP_ATOMIC - Allocation will not sleep. May use emergency pools. - * For example, use this inside interrupt handlers. - * - * %GFP_HIGHUSER - Allocate pages from high memory. - * - * %GFP_NOIO - Do not do any I/O at all while trying to get memory. - * - * %GFP_NOFS - Do not make any fs calls while trying to get memory. - * - * %GFP_NOWAIT - Allocation will not sleep. - * - * %GFP_THISNODE - Allocate node-local memory only. - * - * %GFP_DMA - Allocation suitable for DMA. - * Should only be used for kmalloc() caches. Otherwise, use a - * slab created with SLAB_DMA. - * - * Also it is possible to set different flags by OR'ing - * in one or more of the following additional @flags: - * - * %__GFP_COLD - Request cache-cold pages instead of - * trying to return cache-warm pages. - * - * %__GFP_HIGH - This allocation has high priority and may use emergency pools. - * - * %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail - * (think twice before using). - * - * %__GFP_NORETRY - If memory is not immediately available, - * then give up at once. - * - * %__GFP_NOWARN - If allocation fails, don't issue any warnings. - * - * %__GFP_REPEAT - If allocation fails initially, try once more before failing. - * - * There are other flags available as well, but these are not intended - * for general use, and so are not documented here. For a full list of - * potential flags, always refer to linux/gfp.h. - * - * kmalloc is the normal method of allocating memory - * in the kernel. - */ -static __always_inline void *kmalloc(size_t size, gfp_t flags); - /** * kmalloc_array - allocate memory for an array. * @n: number of elements. -- cgit v1.2.3-59-g8ed1b From f37ff6b6ab9bff6f78dbfbdd123673a09e04cb7f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 17 Dec 2013 14:23:17 +0100 Subject: regulator: s5m8767: Add symbols for hard-coded DVS_RAMP register Add symbols for hard-coded values of BUCK_RAMP field in DVS_RAMP register. This simplifies a little the code as register update is called only once. Signed-off-by: Krzysztof Kozlowski Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/s5m8767.c | 22 ++++++++++------------ include/linux/mfd/samsung/s5m8767.h | 15 +++++++++++++++ 2 files changed, 25 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index 9b14faa3bf91..27741df28ad7 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -881,31 +881,29 @@ static int s5m8767_pmic_probe(struct platform_device *pdev) if (s5m8767->buck2_ramp || s5m8767->buck3_ramp || s5m8767->buck4_ramp) { + unsigned int val; switch (s5m8767->ramp_delay) { case 5: - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0x40, 0xf0); + val = S5M8767_DVS_BUCK_RAMP_5; break; case 10: - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0x90, 0xf0); + val = S5M8767_DVS_BUCK_RAMP_10; break; case 25: - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0xd0, 0xf0); + val = S5M8767_DVS_BUCK_RAMP_25; break; case 50: - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0xe0, 0xf0); + val = S5M8767_DVS_BUCK_RAMP_50; break; case 100: - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0xf0, 0xf0); + val = S5M8767_DVS_BUCK_RAMP_100; break; default: - sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, - 0x90, 0xf0); + val = S5M8767_DVS_BUCK_RAMP_10; } + sec_reg_update(s5m8767->iodev, S5M8767_REG_DVSRAMP, + val << S5M8767_DVS_BUCK_RAMP_SHIFT, + S5M8767_DVS_BUCK_RAMP_MASK); } for (i = 0; i < pdata->num_regulators; i++) { diff --git a/include/linux/mfd/samsung/s5m8767.h b/include/linux/mfd/samsung/s5m8767.h index 9198377ee859..2ab0b0f03641 100644 --- a/include/linux/mfd/samsung/s5m8767.h +++ b/include/linux/mfd/samsung/s5m8767.h @@ -186,4 +186,19 @@ enum s5m8767_regulators { #define S5M8767_ENCTRL_SHIFT 6 #define S5M8767_ENCTRL_MASK (0x3 << S5M8767_ENCTRL_SHIFT) +/* + * Values for BUCK_RAMP field in DVS_RAMP register, matching raw values + * in mV/us. + */ +enum s5m8767_dvs_buck_ramp_values { + S5M8767_DVS_BUCK_RAMP_5 = 0x4, + S5M8767_DVS_BUCK_RAMP_10 = 0x9, + S5M8767_DVS_BUCK_RAMP_12_5 = 0xb, + S5M8767_DVS_BUCK_RAMP_25 = 0xd, + S5M8767_DVS_BUCK_RAMP_50 = 0xe, + S5M8767_DVS_BUCK_RAMP_100 = 0xf, +}; +#define S5M8767_DVS_BUCK_RAMP_SHIFT 4 +#define S5M8767_DVS_BUCK_RAMP_MASK (0xf << S5M8767_DVS_BUCK_RAMP_SHIFT) + #endif /* __LINUX_MFD_S5M8767_H */ -- cgit v1.2.3-59-g8ed1b From 397321f45d31159c84982978106f3165be44bc2b Mon Sep 17 00:00:00 2001 From: Alexander Popov Date: Mon, 16 Dec 2013 12:12:17 +0400 Subject: dmaengine: fix incorrect kernel-doc comment for struct dma_slave_config The 'direction' member of 'struct dma_slave_config' is of data type 'enum dma_transfer_direction', so update the kernel-doc comment for 'struct dma_slave_config' to refer to appropriate values. Signed-off-by: Alexander Popov Signed-off-by: Vinod Koul --- include/linux/dmaengine.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 41cf0c399288..bd6b88222ced 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -305,9 +305,8 @@ enum dma_slave_buswidth { /** * struct dma_slave_config - dma slave channel runtime config * @direction: whether the data shall go in or out on this slave - * channel, right now. DMA_TO_DEVICE and DMA_FROM_DEVICE are - * legal values, DMA_BIDIRECTIONAL is not acceptable since we - * need to differentiate source and target addresses. + * channel, right now. DMA_MEM_TO_DEV and DMA_DEV_TO_MEM are + * legal values. * @src_addr: this is the physical address where DMA slave data * should be read (RX), if the source is memory this argument is * ignored. -- cgit v1.2.3-59-g8ed1b From ee5182b59f65e7975d8fec73d511f4d6c44f6ed3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 17 Dec 2013 14:23:19 +0100 Subject: mfd: sec: Remove sec_reg* regmap helpers Remove sec_reg* helpers as they are not used anymore. These helpers were error-prone as they mixed u8 with unsigned int and they changed order of some of parameters (val and mask in sec_reg_update()). Also the helpers didn't give any way of useful abstraction as they just called corresponding regmap function. Signed-off-by: Krzysztof Kozlowski Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/mfd/sec-core.c | 30 ------------------------------ include/linux/mfd/samsung/core.h | 6 ------ 2 files changed, 36 deletions(-) (limited to 'include/linux') diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index 54cc25546592..1d158d5ba8b8 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -79,36 +79,6 @@ static struct of_device_id sec_dt_match[] = { }; #endif -int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest) -{ - return regmap_read(sec_pmic->regmap_pmic, reg, dest); -} -EXPORT_SYMBOL_GPL(sec_reg_read); - -int sec_bulk_read(struct sec_pmic_dev *sec_pmic, u8 reg, int count, u8 *buf) -{ - return regmap_bulk_read(sec_pmic->regmap_pmic, reg, buf, count); -} -EXPORT_SYMBOL_GPL(sec_bulk_read); - -int sec_reg_write(struct sec_pmic_dev *sec_pmic, u8 reg, u8 value) -{ - return regmap_write(sec_pmic->regmap_pmic, reg, value); -} -EXPORT_SYMBOL_GPL(sec_reg_write); - -int sec_bulk_write(struct sec_pmic_dev *sec_pmic, u8 reg, int count, u8 *buf) -{ - return regmap_raw_write(sec_pmic->regmap_pmic, reg, buf, count); -} -EXPORT_SYMBOL_GPL(sec_bulk_write); - -int sec_reg_update(struct sec_pmic_dev *sec_pmic, u8 reg, u8 val, u8 mask) -{ - return regmap_update_bits(sec_pmic->regmap_pmic, reg, mask, val); -} -EXPORT_SYMBOL_GPL(sec_reg_update); - static bool s2mps11_volatile(struct device *dev, unsigned int reg) { switch (reg) { diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h index cab2dd279076..41c9bde410c5 100644 --- a/include/linux/mfd/samsung/core.h +++ b/include/linux/mfd/samsung/core.h @@ -59,12 +59,6 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic); void sec_irq_exit(struct sec_pmic_dev *sec_pmic); int sec_irq_resume(struct sec_pmic_dev *sec_pmic); -extern int sec_reg_read(struct sec_pmic_dev *sec_pmic, u8 reg, void *dest); -extern int sec_bulk_read(struct sec_pmic_dev *sec_pmic, u8 reg, int count, u8 *buf); -extern int sec_reg_write(struct sec_pmic_dev *sec_pmic, u8 reg, u8 value); -extern int sec_bulk_write(struct sec_pmic_dev *sec_pmic, u8 reg, int count, u8 *buf); -extern int sec_reg_update(struct sec_pmic_dev *sec_pmic, u8 reg, u8 val, u8 mask); - struct sec_platform_data { struct sec_regulator_data *regulators; struct sec_opmode_data *opmode; -- cgit v1.2.3-59-g8ed1b From 93b36cf3425b9bd9c56df7680fb237686b9c82ae Mon Sep 17 00:00:00 2001 From: Hannes Frederic Sowa Date: Sun, 15 Dec 2013 03:41:14 +0100 Subject: ipv6: support IPV6_PMTU_INTERFACE on sockets IPV6_PMTU_INTERFACE is the same as IPV6_PMTU_PROBE for ipv6. Add it nontheless for symmetry with IPv4 sockets. Also drop incoming MTU information if this mode is enabled. The additional bit in ipv6_pinfo just eats in the padding behind the bitfield. There are no changes to the layout of the struct at all. Signed-off-by: Hannes Frederic Sowa Signed-off-by: David S. Miller --- include/linux/ipv6.h | 2 +- include/net/ip6_route.h | 7 ++++++- include/uapi/linux/in6.h | 4 ++++ net/dccp/ipv6.c | 3 +++ net/ipv6/ip6_output.c | 6 +++--- net/ipv6/ipv6_sockglue.c | 2 +- net/ipv6/tcp_ipv6.c | 3 +++ net/ipv6/udp.c | 5 ++++- net/sctp/input.c | 3 +++ 9 files changed, 28 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 3fde06645553..7e1ded0d8e45 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -191,7 +191,7 @@ struct ipv6_pinfo { /* sockopt flags */ __u16 recverr:1, sndflow:1, - pmtudisc:2, + pmtudisc:3, ipv6only:1, srcprefs:3, /* 001: prefer temporary address * 010: prefer public address diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index 733747ce163c..c2626ce1f2ad 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -178,10 +178,15 @@ static inline int ip6_skb_dst_mtu(struct sk_buff *skb) { struct ipv6_pinfo *np = skb->sk ? inet6_sk(skb->sk) : NULL; - return (np && np->pmtudisc == IPV6_PMTUDISC_PROBE) ? + return (np && np->pmtudisc >= IPV6_PMTUDISC_PROBE) ? skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); } +static inline bool ip6_sk_accept_pmtu(const struct sock *sk) +{ + return inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_INTERFACE; +} + static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt) { return &rt->rt6i_gateway; diff --git a/include/uapi/linux/in6.h b/include/uapi/linux/in6.h index 440d5c479145..f94f1d013bf2 100644 --- a/include/uapi/linux/in6.h +++ b/include/uapi/linux/in6.h @@ -188,6 +188,10 @@ enum { #define IPV6_PMTUDISC_WANT 1 #define IPV6_PMTUDISC_DO 2 #define IPV6_PMTUDISC_PROBE 3 +/* same as IPV6_PMTUDISC_PROBE, provided for symetry with IPv4 + * also see comments on IP_PMTUDISC_INTERFACE + */ +#define IPV6_PMTUDISC_INTERFACE 4 /* Flowlabel */ #define IPV6_FLOWLABEL_MGR 32 diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 2b90a786e475..629019e6f8e9 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -141,6 +141,9 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (type == ICMPV6_PKT_TOOBIG) { struct dst_entry *dst = NULL; + if (!ip6_sk_accept_pmtu(sk)) + goto out; + if (sock_owned_by_user(sk)) goto out; if ((1 << sk->sk_state) & (DCCPF_LISTEN | DCCPF_CLOSED)) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 9a311cc79672..bc4e1bcdf4c0 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1165,10 +1165,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, np->cork.hop_limit = hlimit; np->cork.tclass = tclass; if (rt->dst.flags & DST_XFRM_TUNNEL) - mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? + mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? rt->dst.dev->mtu : dst_mtu(&rt->dst); else - mtu = np->pmtudisc == IPV6_PMTUDISC_PROBE ? + mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? rt->dst.dev->mtu : dst_mtu(rt->dst.path); if (np->frag_size < mtu) { if (np->frag_size) @@ -1270,7 +1270,7 @@ alloc_new_skb: if (skb == NULL || skb_prev == NULL) ip6_append_data_mtu(&mtu, &maxfraglen, fragheaderlen, skb, rt, - np->pmtudisc == + np->pmtudisc >= IPV6_PMTUDISC_PROBE); skb_prev = skb; diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 759fbf96515b..af0ecb94b3b4 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -722,7 +722,7 @@ done: case IPV6_MTU_DISCOVER: if (optlen < sizeof(int)) goto e_inval; - if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_PROBE) + if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_INTERFACE) goto e_inval; np->pmtudisc = val; retv = 0; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index da046a5d7ffb..d955487f2c54 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -397,6 +397,9 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (sk->sk_state == TCP_LISTEN) goto out; + if (!ip6_sk_accept_pmtu(sk)) + goto out; + tp->mtu_info = ntohl(info); if (!sock_owned_by_user(sk)) tcp_v6_mtu_reduced(sk); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 089c741a3992..65ed5cd79264 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -538,8 +538,11 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, if (sk == NULL) return; - if (type == ICMPV6_PKT_TOOBIG) + if (type == ICMPV6_PKT_TOOBIG) { + if (!ip6_sk_accept_pmtu(sk)) + goto out; ip6_sk_update_pmtu(skb, sk, info); + } if (type == NDISC_REDIRECT) { ip6_sk_redirect(skb, sk); goto out; diff --git a/net/sctp/input.c b/net/sctp/input.c index 2a192a7c5d81..042ec6c9ae24 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c @@ -389,6 +389,9 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, if (!t || (t->pathmtu <= pmtu)) return; + if (!ip6_sk_accept_pmtu(sk)) + return; + if (sock_owned_by_user(sk)) { asoc->pmtu_pending = 1; t->pmtu_pending = 1; -- cgit v1.2.3-59-g8ed1b From e12348c6d0f720f0f8d665847057b5752e563982 Mon Sep 17 00:00:00 2001 From: Chuansheng Liu Date: Wed, 18 Dec 2013 15:48:23 +0800 Subject: tty: Removing the deprecated function tty_vhangup_locked() The function tty_vhangup_locked() was deprecated, removed it from the tty.h also. Signed-off-by: Liu, Chuansheng Signed-off-by: Greg Kroah-Hartman --- include/linux/tty.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/tty.h b/include/linux/tty.h index ad98b4376968..978d0f09d039 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -427,7 +427,6 @@ extern int is_ignored(int sig); extern int tty_signal(int sig, struct tty_struct *tty); extern void tty_hangup(struct tty_struct *tty); extern void tty_vhangup(struct tty_struct *tty); -extern void tty_vhangup_locked(struct tty_struct *tty); extern void tty_unhangup(struct file *filp); extern int tty_hung_up_p(struct file *filp); extern void do_SAK(struct tty_struct *tty); -- cgit v1.2.3-59-g8ed1b From 4de6a2d6acb0e2a840f07db17def7e674b9d2bb4 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 2 Sep 2013 09:48:53 +0200 Subject: gpu: host1x: Add MIPI pad calibration support This driver adds support to perform calibration of the MIPI pads for CSI and DSI. Signed-off-by: Thierry Reding --- drivers/gpu/host1x/Makefile | 1 + drivers/gpu/host1x/dev.c | 17 ++- drivers/gpu/host1x/dev.h | 2 + drivers/gpu/host1x/mipi.c | 272 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/host1x.h | 6 + 5 files changed, 294 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/host1x/mipi.c (limited to 'include/linux') diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile index afa1e9e4e512..de305c2d510e 100644 --- a/drivers/gpu/host1x/Makefile +++ b/drivers/gpu/host1x/Makefile @@ -7,6 +7,7 @@ host1x-y = \ channel.o \ job.o \ debug.o \ + mipi.o \ hw/host1x01.o \ hw/host1x02.o diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 80da003d63de..646a333b069a 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -210,17 +210,26 @@ static int __init tegra_host1x_init(void) return err; err = platform_driver_register(&tegra_host1x_driver); - if (err < 0) { - host1x_bus_exit(); - return err; - } + if (err < 0) + goto unregister_bus; + + err = platform_driver_register(&tegra_mipi_driver); + if (err < 0) + goto unregister_host1x; return 0; + +unregister_host1x: + platform_driver_unregister(&tegra_host1x_driver); +unregister_bus: + host1x_bus_exit(); + return err; } module_init(tegra_host1x_init); static void __exit tegra_host1x_exit(void) { + platform_driver_unregister(&tegra_mipi_driver); platform_driver_unregister(&tegra_host1x_driver); host1x_bus_exit(); } diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index a61a976e7a42..0b6e8e9629c5 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h @@ -306,4 +306,6 @@ static inline void host1x_hw_show_mlocks(struct host1x *host, struct output *o) host->debug_op->show_mlocks(host, o); } +extern struct platform_driver tegra_mipi_driver; + #endif diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c new file mode 100644 index 000000000000..518b98dd3087 --- /dev/null +++ b/drivers/gpu/host1x/mipi.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2013 NVIDIA Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#define MIPI_CAL_CTRL 0x00 +#define MIPI_CAL_CTRL_START (1 << 0) + +#define MIPI_CAL_AUTOCAL_CTRL 0x01 + +#define MIPI_CAL_STATUS 0x02 +#define MIPI_CAL_STATUS_DONE (1 << 16) +#define MIPI_CAL_STATUS_ACTIVE (1 << 0) + +#define MIPI_CAL_CONFIG_CSIA 0x05 +#define MIPI_CAL_CONFIG_CSIB 0x06 +#define MIPI_CAL_CONFIG_CSIC 0x07 +#define MIPI_CAL_CONFIG_CSID 0x08 +#define MIPI_CAL_CONFIG_CSIE 0x09 +#define MIPI_CAL_CONFIG_DSIA 0x0e +#define MIPI_CAL_CONFIG_DSIB 0x0f +#define MIPI_CAL_CONFIG_DSIC 0x10 +#define MIPI_CAL_CONFIG_DSID 0x11 + +#define MIPI_CAL_CONFIG_SELECT (1 << 21) +#define MIPI_CAL_CONFIG_HSPDOS(x) (((x) & 0x1f) << 16) +#define MIPI_CAL_CONFIG_HSPUOS(x) (((x) & 0x1f) << 8) +#define MIPI_CAL_CONFIG_TERMOS(x) (((x) & 0x1f) << 0) + +#define MIPI_CAL_BIAS_PAD_CFG0 0x16 +#define MIPI_CAL_BIAS_PAD_PDVCLAMP (1 << 1) +#define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF (1 << 0) + +#define MIPI_CAL_BIAS_PAD_CFG1 0x17 + +#define MIPI_CAL_BIAS_PAD_CFG2 0x18 +#define MIPI_CAL_BIAS_PAD_PDVREG (1 << 1) + +static const struct module { + unsigned long reg; +} modules[] = { + { .reg = MIPI_CAL_CONFIG_CSIA }, + { .reg = MIPI_CAL_CONFIG_CSIB }, + { .reg = MIPI_CAL_CONFIG_CSIC }, + { .reg = MIPI_CAL_CONFIG_CSID }, + { .reg = MIPI_CAL_CONFIG_CSIE }, + { .reg = MIPI_CAL_CONFIG_DSIA }, + { .reg = MIPI_CAL_CONFIG_DSIB }, + { .reg = MIPI_CAL_CONFIG_DSIC }, + { .reg = MIPI_CAL_CONFIG_DSID }, +}; + +struct tegra_mipi { + void __iomem *regs; + struct mutex lock; + struct clk *clk; +}; + +struct tegra_mipi_device { + struct platform_device *pdev; + struct tegra_mipi *mipi; + struct device *device; + unsigned long pads; +}; + +static inline unsigned long tegra_mipi_readl(struct tegra_mipi *mipi, + unsigned long reg) +{ + return readl(mipi->regs + (reg << 2)); +} + +static inline void tegra_mipi_writel(struct tegra_mipi *mipi, + unsigned long value, unsigned long reg) +{ + writel(value, mipi->regs + (reg << 2)); +} + +struct tegra_mipi_device *tegra_mipi_request(struct device *device) +{ + struct device_node *np = device->of_node; + struct tegra_mipi_device *dev; + struct of_phandle_args args; + int err; + + err = of_parse_phandle_with_args(np, "nvidia,mipi-calibrate", + "#nvidia,mipi-calibrate-cells", 0, + &args); + if (err < 0) + return ERR_PTR(err); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + of_node_put(args.np); + err = -ENOMEM; + goto out; + } + + dev->pdev = of_find_device_by_node(args.np); + if (!dev->pdev) { + of_node_put(args.np); + err = -ENODEV; + goto free; + } + + of_node_put(args.np); + + dev->mipi = platform_get_drvdata(dev->pdev); + if (!dev->mipi) { + err = -EPROBE_DEFER; + goto pdev_put; + } + + dev->pads = args.args[0]; + dev->device = device; + + return dev; + +pdev_put: + platform_device_put(dev->pdev); +free: + kfree(dev); +out: + return ERR_PTR(err); +} +EXPORT_SYMBOL(tegra_mipi_request); + +void tegra_mipi_free(struct tegra_mipi_device *device) +{ + platform_device_put(device->pdev); + kfree(device); +} +EXPORT_SYMBOL(tegra_mipi_free); + +static int tegra_mipi_wait(struct tegra_mipi *mipi) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(250); + unsigned long value; + + while (time_before(jiffies, timeout)) { + value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS); + if ((value & MIPI_CAL_STATUS_ACTIVE) == 0 && + (value & MIPI_CAL_STATUS_DONE) != 0) + return 0; + + usleep_range(10, 50); + } + + return -ETIMEDOUT; +} + +int tegra_mipi_calibrate(struct tegra_mipi_device *device) +{ + unsigned long value; + unsigned int i; + int err; + + err = clk_enable(device->mipi->clk); + if (err < 0) + return err; + + mutex_lock(&device->mipi->lock); + + value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG0); + value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP; + value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF; + tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0); + + value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2); + value &= ~MIPI_CAL_BIAS_PAD_PDVREG; + tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2); + + for (i = 0; i < ARRAY_SIZE(modules); i++) { + if (device->pads & BIT(i)) + value = MIPI_CAL_CONFIG_SELECT | + MIPI_CAL_CONFIG_HSPDOS(0) | + MIPI_CAL_CONFIG_HSPUOS(4) | + MIPI_CAL_CONFIG_TERMOS(5); + else + value = 0; + + tegra_mipi_writel(device->mipi, value, modules[i].reg); + } + + tegra_mipi_writel(device->mipi, MIPI_CAL_CTRL_START, MIPI_CAL_CTRL); + + err = tegra_mipi_wait(device->mipi); + + mutex_unlock(&device->mipi->lock); + clk_disable(device->mipi->clk); + + return err; +} +EXPORT_SYMBOL(tegra_mipi_calibrate); + +static int tegra_mipi_probe(struct platform_device *pdev) +{ + struct tegra_mipi *mipi; + struct resource *res; + int err; + + mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL); + if (!mipi) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mipi->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mipi->regs)) + return PTR_ERR(mipi->regs); + + mutex_init(&mipi->lock); + + mipi->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(mipi->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + return PTR_ERR(mipi->clk); + } + + err = clk_prepare(mipi->clk); + if (err < 0) + return err; + + platform_set_drvdata(pdev, mipi); + + return 0; +} + +static int tegra_mipi_remove(struct platform_device *pdev) +{ + struct tegra_mipi *mipi = platform_get_drvdata(pdev); + + clk_unprepare(mipi->clk); + + return 0; +} + +static struct of_device_id tegra_mipi_of_match[] = { + { .compatible = "nvidia,tegra114-mipi", }, + { }, +}; + +struct platform_driver tegra_mipi_driver = { + .driver = { + .name = "tegra-mipi", + .of_match_table = tegra_mipi_of_match, + }, + .probe = tegra_mipi_probe, + .remove = tegra_mipi_remove, +}; diff --git a/include/linux/host1x.h b/include/linux/host1x.h index f5b9b87ac9a9..3af847273277 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -281,4 +281,10 @@ int host1x_device_exit(struct host1x_device *device); int host1x_client_register(struct host1x_client *client); int host1x_client_unregister(struct host1x_client *client); +struct tegra_mipi_device; + +struct tegra_mipi_device *tegra_mipi_request(struct device *device); +void tegra_mipi_free(struct tegra_mipi_device *device); +int tegra_mipi_calibrate(struct tegra_mipi_device *device); + #endif -- cgit v1.2.3-59-g8ed1b From 792b62e705048f4da9a6f570c15093ab669839b6 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 19 Dec 2013 09:11:01 +0000 Subject: mfd: wm5110: Expose DRE control registers Certain use-cases require the DRE to be disabled so expose registers necessary to control the DRE enables. Signed-off-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/mfd/wm5110-tables.c | 2 ++ include/linux/mfd/arizona/registers.h | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'include/linux') diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 338cfbe6727b..abd6713de7b0 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -601,6 +601,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x0000043D, 0x0180 }, /* R1085 - DAC Digital Volume 6R */ { 0x0000043E, 0x0080 }, /* R1086 - DAC Volume Limit 6R */ { 0x0000043F, 0x0800 }, /* R1087 - Noise Gate Select 6R */ + { 0x00000440, 0x8FFF }, /* R1088 - DRE Enable */ { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */ { 0x00000458, 0x0000 }, /* R1112 - Noise Gate Control */ { 0x00000480, 0x0040 }, /* R1152 - Class W ANC Threshold 1 */ @@ -1631,6 +1632,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_DAC_DIGITAL_VOLUME_6R: case ARIZONA_DAC_VOLUME_LIMIT_6R: case ARIZONA_NOISE_GATE_SELECT_6R: + case ARIZONA_DRE_ENABLE: case ARIZONA_DAC_AEC_CONTROL_1: case ARIZONA_NOISE_GATE_CONTROL: case ARIZONA_PDM_SPK1_CTRL_1: diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 89878149a43f..22916c0f1ca4 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -3207,6 +3207,10 @@ /* * R1088 (0x440) - DRE Enable */ +#define ARIZONA_DRE3R_ENA 0x0020 /* DRE3R_ENA */ +#define ARIZONA_DRE3R_ENA_MASK 0x0020 /* DRE3R_ENA */ +#define ARIZONA_DRE3R_ENA_SHIFT 5 /* DRE3R_ENA */ +#define ARIZONA_DRE3R_ENA_WIDTH 1 /* DRE3R_ENA */ #define ARIZONA_DRE3L_ENA 0x0010 /* DRE3L_ENA */ #define ARIZONA_DRE3L_ENA_MASK 0x0010 /* DRE3L_ENA */ #define ARIZONA_DRE3L_ENA_SHIFT 4 /* DRE3L_ENA */ -- cgit v1.2.3-59-g8ed1b From c4b34a3b7a505dd63268cf6dcf57d10068b47cb6 Mon Sep 17 00:00:00 2001 From: George Cherian Date: Tue, 15 Oct 2013 15:32:14 +0530 Subject: usb: phy: omap: Add omap-control Support for AM437x This adds omap control module support for USBSS in AM437x SoC. Update DT binding information to reflect these changes. Acked-by: Roger Quadros Signed-off-by: George Cherian Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/omap-usb.txt | 2 ++ drivers/usb/phy/phy-omap-control.c | 19 +++++++++++++++++++ include/linux/usb/omap_control_usb.h | 6 ++++++ 3 files changed, 27 insertions(+) (limited to 'include/linux') diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt index 090e5e22bd2b..c495135115cb 100644 --- a/Documentation/devicetree/bindings/usb/omap-usb.txt +++ b/Documentation/devicetree/bindings/usb/omap-usb.txt @@ -87,6 +87,8 @@ Required properties: e.g. USB3 PHY and SATA PHY on OMAP5. "ti,control-phy-dra7usb2" - if it has power down register like USB2 PHY on DRA7 platform. + "ti,control-phy-am437usb2" - if it has power down register like USB2 PHY on + AM437 platform. - reg : Address and length of the register set for the device. It contains the address of "otghs_control" for control-phy-otghs or "power" register for other types. diff --git a/drivers/usb/phy/phy-omap-control.c b/drivers/usb/phy/phy-omap-control.c index 09c5ace1edd8..e7253182e47d 100644 --- a/drivers/usb/phy/phy-omap-control.c +++ b/drivers/usb/phy/phy-omap-control.c @@ -84,6 +84,20 @@ void omap_control_usb_phy_power(struct device *dev, int on) else val |= OMAP_CTRL_USB2_PHY_PD; break; + + case OMAP_CTRL_TYPE_AM437USB2: + if (on) { + val &= ~(AM437X_CTRL_USB2_PHY_PD | + AM437X_CTRL_USB2_OTG_PD); + val |= (AM437X_CTRL_USB2_OTGVDET_EN | + AM437X_CTRL_USB2_OTGSESSEND_EN); + } else { + val &= ~(AM437X_CTRL_USB2_OTGVDET_EN | + AM437X_CTRL_USB2_OTGSESSEND_EN); + val |= (AM437X_CTRL_USB2_PHY_PD | + AM437X_CTRL_USB2_OTG_PD); + } + break; default: dev_err(dev, "%s: type %d not recognized\n", __func__, control_usb->type); @@ -197,6 +211,7 @@ static const enum omap_control_usb_type otghs_data = OMAP_CTRL_TYPE_OTGHS; static const enum omap_control_usb_type usb2_data = OMAP_CTRL_TYPE_USB2; static const enum omap_control_usb_type pipe3_data = OMAP_CTRL_TYPE_PIPE3; static const enum omap_control_usb_type dra7usb2_data = OMAP_CTRL_TYPE_DRA7USB2; +static const enum omap_control_usb_type am437usb2_data = OMAP_CTRL_TYPE_AM437USB2; static const struct of_device_id omap_control_usb_id_table[] = { { @@ -215,6 +230,10 @@ static const struct of_device_id omap_control_usb_id_table[] = { .compatible = "ti,control-phy-dra7usb2", .data = &dra7usb2_data, }, + { + .compatible = "ti,control-phy-am437usb2", + .data = &am437usb2_data, + }, {}, }; MODULE_DEVICE_TABLE(of, omap_control_usb_id_table); diff --git a/include/linux/usb/omap_control_usb.h b/include/linux/usb/omap_control_usb.h index 596b01918813..69ae383ee3cc 100644 --- a/include/linux/usb/omap_control_usb.h +++ b/include/linux/usb/omap_control_usb.h @@ -24,6 +24,7 @@ enum omap_control_usb_type { OMAP_CTRL_TYPE_USB2, /* USB2_PHY, power down in CONTROL_DEV_CONF */ OMAP_CTRL_TYPE_PIPE3, /* PIPE3 PHY, DPLL & seperate Rx/Tx power */ OMAP_CTRL_TYPE_DRA7USB2, /* USB2 PHY, power and power_aux e.g. DRA7 */ + OMAP_CTRL_TYPE_AM437USB2, /* USB2 PHY, power e.g. AM437x */ }; struct omap_control_usb { @@ -64,6 +65,11 @@ enum omap_control_usb_mode { #define OMAP_CTRL_USB2_PHY_PD BIT(28) +#define AM437X_CTRL_USB2_PHY_PD BIT(0) +#define AM437X_CTRL_USB2_OTG_PD BIT(1) +#define AM437X_CTRL_USB2_OTGVDET_EN BIT(19) +#define AM437X_CTRL_USB2_OTGSESSEND_EN BIT(20) + #if IS_ENABLED(CONFIG_OMAP_CONTROL_USB) extern void omap_control_usb_phy_power(struct device *dev, int on); extern void omap_control_usb_set_mode(struct device *dev, -- cgit v1.2.3-59-g8ed1b From 8dcf94bcff5bf3b54380ae2a17b034fb3b9d58e5 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 19 Dec 2013 10:17:11 -0700 Subject: misc: Reserve minor for VFIO VFIO currently allocates it's own dynamic chardev range, reserving the first minor for the control part of the interface (/dev/vfio/vfio) and the remainder for VFIO groups (/dev/vfio/$GROUP). This works, but it doesn't support auto loading. For instance when libvirt checks for VFIO support it looks for /dev/vfio/vfio, which currently doesn't exist unless the vfio module is loaded. By converting the control device to a misc driver and reserving a static minor, we can enable auto loading. Reserving the minor is a prerequist to that conversion. Minor 196 is unused by anything currently in the kernel. Suggested-by: Paolo Bonzini Signed-off-by: Alex Williamson Acked-by: Greg Kroah-Hartman --- Documentation/devices.txt | 1 + include/linux/miscdevice.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include/linux') diff --git a/Documentation/devices.txt b/Documentation/devices.txt index 80b72419ffd8..10378cc48374 100644 --- a/Documentation/devices.txt +++ b/Documentation/devices.txt @@ -409,6 +409,7 @@ Your cooperation is appreciated. 193 = /dev/d7s SPARC 7-segment display 194 = /dev/zkshim Zero-Knowledge network shim control 195 = /dev/elographics/e2201 Elographics touchscreen E271-2201 + 196 = /dev/vfio/vfio VFIO userspace driver interface 198 = /dev/sexec Signed executable interface 199 = /dev/scanners/cuecat :CueCat barcode scanner 200 = /dev/net/tun TAP/TUN network device diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index f7eaf2d60083..3737f7218f51 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -30,6 +30,7 @@ #define STORE_QUEUE_MINOR 155 #define I2O_MINOR 166 #define MICROCODE_MINOR 184 +#define VFIO_MINOR 196 #define TUN_MINOR 200 #define CUSE_MINOR 203 #define MWAVE_MINOR 219 /* ACP/Mwave Modem */ -- cgit v1.2.3-59-g8ed1b From 7f4a8e7b1943c1fc7e4b08509e308197babdcd5b Mon Sep 17 00:00:00 2001 From: Vinayak Kale Date: Wed, 4 Dec 2013 10:09:50 +0000 Subject: genirq: Add an accessor for IRQ_PER_CPU flag This patch adds an accessor function for IRQ_PER_CPU flag. The accessor function is useful to determine whether an IRQ is percpu or not. This patch is based on an older patch posted by Chris Smith here [1]. There is a minor change w.r.t. Chris's original patch: The accessor function is renamed as 'irq_is_percpu' instead of 'irq_is_per_cpu'. [1]: http://lkml.indiana.edu/hypermail/linux/kernel/1207.3/02955.html Signed-off-by: Chris Smith Signed-off-by: Vinayak Kale Acked-by: Will Deacon Reviewed-by: Thomas Gleixner Signed-off-by: Will Deacon Signed-off-by: Catalin Marinas --- include/linux/irqdesc.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'include/linux') diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index 56fb646909dc..26e2661d3935 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -152,6 +152,14 @@ static inline int irq_balancing_disabled(unsigned int irq) return desc->status_use_accessors & IRQ_NO_BALANCING_MASK; } +static inline int irq_is_percpu(unsigned int irq) +{ + struct irq_desc *desc; + + desc = irq_to_desc(irq); + return desc->status_use_accessors & IRQ_PER_CPU; +} + static inline void irq_set_lockdep_class(unsigned int irq, struct lock_class_key *class) { -- cgit v1.2.3-59-g8ed1b From 78ea85f17b15390e30d8b47488ec7b6cf0790663 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 16 Dec 2013 23:27:09 +0100 Subject: net: skbuff: improve comment on checksumming It can be a bit confusing when looking for checksumming flags that the actual comment for this resides elsewhere further below in the header file. Thus, bring the documentation where we define these flags, and slightly improve the doc text to make it a bit more clear/readable. Also, whitespace-align values of the define while at it. Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/linux/skbuff.h | 131 ++++++++++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 56 deletions(-) (limited to 'include/linux') diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 06bedeb0d49e..c5cd016f5120 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -34,11 +34,82 @@ #include #include +/* A. Checksumming of received packets by device. + * + * CHECKSUM_NONE: + * + * Device failed to checksum this packet e.g. due to lack of capabilities. + * The packet contains full (though not verified) checksum in packet but + * not in skb->csum. Thus, skb->csum is undefined in this case. + * + * CHECKSUM_UNNECESSARY: + * + * The hardware you're dealing with doesn't calculate the full checksum + * (as in CHECKSUM_COMPLETE), but it does parse headers and verify checksums + * for specific protocols e.g. TCP/UDP/SCTP, then, for such packets it will + * set CHECKSUM_UNNECESSARY if their checksums are okay. skb->csum is still + * undefined in this case though. It is a bad option, but, unfortunately, + * nowadays most vendors do this. Apparently with the secret goal to sell + * you new devices, when you will add new protocol to your host, f.e. IPv6 8) + * + * CHECKSUM_COMPLETE: + * + * This is the most generic way. The device supplied checksum of the _whole_ + * packet as seen by netif_rx() and fills out in skb->csum. Meaning, the + * hardware doesn't need to parse L3/L4 headers to implement this. + * + * Note: Even if device supports only some protocols, but is able to produce + * skb->csum, it MUST use CHECKSUM_COMPLETE, not CHECKSUM_UNNECESSARY. + * + * CHECKSUM_PARTIAL: + * + * This is identical to the case for output below. This may occur on a packet + * received directly from another Linux OS, e.g., a virtualized Linux kernel + * on the same host. The packet can be treated in the same way as + * CHECKSUM_UNNECESSARY, except that on output (i.e., forwarding) the + * checksum must be filled in by the OS or the hardware. + * + * B. Checksumming on output. + * + * CHECKSUM_NONE: + * + * The skb was already checksummed by the protocol, or a checksum is not + * required. + * + * CHECKSUM_PARTIAL: + * + * The device is required to checksum the packet as seen by hard_start_xmit() + * from skb->csum_start up to the end, and to record/write the checksum at + * offset skb->csum_start + skb->csum_offset. + * + * The device must show its capabilities in dev->features, set up at device + * setup time, e.g. netdev_features.h: + * + * NETIF_F_HW_CSUM - It's a clever device, it's able to checksum everything. + * NETIF_F_IP_CSUM - Device is dumb, it's able to checksum only TCP/UDP over + * IPv4. Sigh. Vendors like this way for an unknown reason. + * Though, see comment above about CHECKSUM_UNNECESSARY. 8) + * NETIF_F_IPV6_CSUM - About as dumb as the last one but does IPv6 instead. + * NETIF_F_... - Well, you get the picture. + * + * CHECKSUM_UNNECESSARY: + * + * Normally, the device will do per protocol specific checksumming. Protocol + * implementations that do not want the NIC to perform the checksum + * calculation should use this flag in their outgoing skbs. + * + * NETIF_F_FCOE_CRC - This indicates that the device can do FCoE FC CRC + * offload. Correspondingly, the FCoE protocol driver + * stack should use CHECKSUM_UNNECESSARY. + * + * Any questions? No questions, good. --ANK + */ + /* Don't change this without changing skb_csum_unnecessary! */ -#define CHECKSUM_NONE 0 -#define CHECKSUM_UNNECESSARY 1 -#define CHECKSUM_COMPLETE 2 -#define CHECKSUM_PARTIAL 3 +#define CHECKSUM_NONE 0 +#define CHECKSUM_UNNECESSARY 1 +#define CHECKSUM_COMPLETE 2 +#define CHECKSUM_PARTIAL 3 #define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES - 1)) & \ ~(SMP_CACHE_BYTES - 1)) @@ -54,58 +125,6 @@ SKB_DATA_ALIGN(sizeof(struct sk_buff)) + \ SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) -/* A. Checksumming of received packets by device. - * - * NONE: device failed to checksum this packet. - * skb->csum is undefined. - * - * UNNECESSARY: device parsed packet and wouldbe verified checksum. - * skb->csum is undefined. - * It is bad option, but, unfortunately, many of vendors do this. - * Apparently with secret goal to sell you new device, when you - * will add new protocol to your host. F.e. IPv6. 8) - * - * COMPLETE: the most generic way. Device supplied checksum of _all_ - * the packet as seen by netif_rx in skb->csum. - * NOTE: Even if device supports only some protocols, but - * is able to produce some skb->csum, it MUST use COMPLETE, - * not UNNECESSARY. - * - * PARTIAL: identical to the case for output below. This may occur - * on a packet received directly from another Linux OS, e.g., - * a virtualised Linux kernel on the same host. The packet can - * be treated in the same way as UNNECESSARY except that on - * output (i.e., forwarding) the checksum must be filled in - * by the OS or the hardware. - * - * B. Checksumming on output. - * - * NONE: skb is checksummed by protocol or csum is not required. - * - * PARTIAL: device is required to csum packet as seen by hard_start_xmit - * from skb->csum_start to the end and to record the checksum - * at skb->csum_start + skb->csum_offset. - * - * Device must show its capabilities in dev->features, set - * at device setup time. - * NETIF_F_HW_CSUM - it is clever device, it is able to checksum - * everything. - * NETIF_F_IP_CSUM - device is dumb. It is able to csum only - * TCP/UDP over IPv4. Sigh. Vendors like this - * way by an unknown reason. Though, see comment above - * about CHECKSUM_UNNECESSARY. 8) - * NETIF_F_IPV6_CSUM about as dumb as the last one but does IPv6 instead. - * - * UNNECESSARY: device will do per protocol specific csum. Protocol drivers - * that do not want net to perform the checksum calculation should use - * this flag in their outgoing skbs. - * NETIF_F_FCOE_CRC this indicates the device can do FCoE FC CRC - * offload. Correspondingly, the FCoE protocol driver - * stack should use CHECKSUM_UNNECESSARY. - * - * Any questions? No questions, good. --ANK - */ - struct net_device; struct scatterlist; struct pipe_inode_info; -- cgit v1.2.3-59-g8ed1b From 1c51b50c2995f543d145d3bce78029ac9f8ca6b3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Thu, 19 Dec 2013 12:30:17 -0800 Subject: PCI/MSI: Export MSI mode using attributes, not kobjects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PCI MSI sysfs code is a mess with kobjects for things that don't really need to be kobjects. This patch creates attributes dynamically for the MSI interrupts instead of using kobjects. Note, this removes a directory from sysfs. Old MSI kobjects: pci_device └── msi_irqs    └── 40    └── mode New MSI attributes: pci_device └── msi_irqs    └── 40 As there was only one file "mode" with the kobject model, the interrupt number is now a file that returns the "mode" of the interrupt (msi vs. msix). Signed-off-by: Greg Kroah-Hartman Signed-off-by: Bjorn Helgaas Acked-by: Neil Horman --- Documentation/ABI/testing/sysfs-bus-pci | 11 +-- drivers/pci/msi.c | 166 +++++++++++++++++--------------- include/linux/pci.h | 2 +- 3 files changed, 96 insertions(+), 83 deletions(-) (limited to 'include/linux') diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index 5210a51c90fd..a3c5a6685036 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -70,18 +70,15 @@ Date: September, 2011 Contact: Neil Horman Description: The /sys/devices/.../msi_irqs directory contains a variable set - of sub-directories, with each sub-directory being named after a - corresponding msi irq vector allocated to that device. Each - numbered sub-directory N contains attributes of that irq. - Note that this directory is not created for device drivers which - do not support msi irqs + of files, with each file being named after a corresponding msi + irq vector allocated to that device. -What: /sys/bus/pci/devices/.../msi_irqs//mode +What: /sys/bus/pci/devices/.../msi_irqs/ Date: September 2011 Contact: Neil Horman Description: This attribute indicates the mode that the irq vector named by - the parent directory is in (msi vs. msix) + the file is in (msi vs. msix) What: /sys/bus/pci/devices/.../remove Date: January 2009 diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 3fcd67a16677..f88fa1277802 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -363,6 +363,9 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) static void free_msi_irqs(struct pci_dev *dev) { struct msi_desc *entry, *tmp; + struct attribute **msi_attrs; + struct device_attribute *dev_attr; + int count = 0; list_for_each_entry(entry, &dev->msi_list, list) { int i, nvec; @@ -398,6 +401,22 @@ static void free_msi_irqs(struct pci_dev *dev) list_del(&entry->list); kfree(entry); } + + if (dev->msi_irq_groups) { + sysfs_remove_groups(&dev->dev.kobj, dev->msi_irq_groups); + msi_attrs = dev->msi_irq_groups[0]->attrs; + list_for_each_entry(entry, &dev->msi_list, list) { + dev_attr = container_of(msi_attrs[count], + struct device_attribute, attr); + kfree(dev_attr->attr.name); + kfree(dev_attr); + ++count; + } + kfree(msi_attrs); + kfree(dev->msi_irq_groups[0]); + kfree(dev->msi_irq_groups); + dev->msi_irq_groups = NULL; + } } static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) @@ -471,94 +490,95 @@ void pci_restore_msi_state(struct pci_dev *dev) } EXPORT_SYMBOL_GPL(pci_restore_msi_state); - -#define to_msi_attr(obj) container_of(obj, struct msi_attribute, attr) -#define to_msi_desc(obj) container_of(obj, struct msi_desc, kobj) - -struct msi_attribute { - struct attribute attr; - ssize_t (*show)(struct msi_desc *entry, struct msi_attribute *attr, - char *buf); - ssize_t (*store)(struct msi_desc *entry, struct msi_attribute *attr, - const char *buf, size_t count); -}; - -static ssize_t show_msi_mode(struct msi_desc *entry, struct msi_attribute *atr, +static ssize_t msi_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%s\n", entry->msi_attrib.is_msix ? "msix" : "msi"); -} - -static ssize_t msi_irq_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct msi_attribute *attribute = to_msi_attr(attr); - struct msi_desc *entry = to_msi_desc(kobj); - - if (!attribute->show) - return -EIO; - - return attribute->show(entry, attribute, buf); -} - -static const struct sysfs_ops msi_irq_sysfs_ops = { - .show = msi_irq_attr_show, -}; - -static struct msi_attribute mode_attribute = - __ATTR(mode, S_IRUGO, show_msi_mode, NULL); - - -static struct attribute *msi_irq_default_attrs[] = { - &mode_attribute.attr, - NULL -}; + struct pci_dev *pdev = to_pci_dev(dev); + struct msi_desc *entry; + unsigned long irq; + int retval; -static void msi_kobj_release(struct kobject *kobj) -{ - struct msi_desc *entry = to_msi_desc(kobj); + retval = kstrtoul(attr->attr.name, 10, &irq); + if (retval) + return retval; - pci_dev_put(entry->dev); + list_for_each_entry(entry, &pdev->msi_list, list) { + if (entry->irq == irq) { + return sprintf(buf, "%s\n", + entry->msi_attrib.is_msix ? "msix" : "msi"); + } + } + return -ENODEV; } -static struct kobj_type msi_irq_ktype = { - .release = msi_kobj_release, - .sysfs_ops = &msi_irq_sysfs_ops, - .default_attrs = msi_irq_default_attrs, -}; - static int populate_msi_sysfs(struct pci_dev *pdev) { + struct attribute **msi_attrs; + struct attribute *msi_attr; + struct device_attribute *msi_dev_attr; + struct attribute_group *msi_irq_group; + const struct attribute_group **msi_irq_groups; struct msi_desc *entry; - struct kobject *kobj; - int ret; + int ret = -ENOMEM; + int num_msi = 0; int count = 0; - pdev->msi_kset = kset_create_and_add("msi_irqs", NULL, &pdev->dev.kobj); - if (!pdev->msi_kset) - return -ENOMEM; + /* Determine how many msi entries we have */ + list_for_each_entry(entry, &pdev->msi_list, list) { + ++num_msi; + } + if (!num_msi) + return 0; + /* Dynamically create the MSI attributes for the PCI device */ + msi_attrs = kzalloc(sizeof(void *) * (num_msi + 1), GFP_KERNEL); + if (!msi_attrs) + return -ENOMEM; list_for_each_entry(entry, &pdev->msi_list, list) { - kobj = &entry->kobj; - kobj->kset = pdev->msi_kset; - pci_dev_get(pdev); - ret = kobject_init_and_add(kobj, &msi_irq_ktype, NULL, - "%u", entry->irq); - if (ret) - goto out_unroll; - - count++; + char *name = kmalloc(20, GFP_KERNEL); + msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL); + if (!msi_dev_attr) + goto error_attrs; + sprintf(name, "%d", entry->irq); + sysfs_attr_init(&msi_dev_attr->attr); + msi_dev_attr->attr.name = name; + msi_dev_attr->attr.mode = S_IRUGO; + msi_dev_attr->show = msi_mode_show; + msi_attrs[count] = &msi_dev_attr->attr; + ++count; } + msi_irq_group = kzalloc(sizeof(*msi_irq_group), GFP_KERNEL); + if (!msi_irq_group) + goto error_attrs; + msi_irq_group->name = "msi_irqs"; + msi_irq_group->attrs = msi_attrs; + + msi_irq_groups = kzalloc(sizeof(void *) * 2, GFP_KERNEL); + if (!msi_irq_groups) + goto error_irq_group; + msi_irq_groups[0] = msi_irq_group; + + ret = sysfs_create_groups(&pdev->dev.kobj, msi_irq_groups); + if (ret) + goto error_irq_groups; + pdev->msi_irq_groups = msi_irq_groups; + return 0; -out_unroll: - list_for_each_entry(entry, &pdev->msi_list, list) { - if (!count) - break; - kobject_del(&entry->kobj); - kobject_put(&entry->kobj); - count--; +error_irq_groups: + kfree(msi_irq_groups); +error_irq_group: + kfree(msi_irq_group); +error_attrs: + count = 0; + msi_attr = msi_attrs[count]; + while (msi_attr) { + msi_dev_attr = container_of(msi_attr, struct device_attribute, attr); + kfree(msi_attr->name); + kfree(msi_dev_attr); + ++count; + msi_attr = msi_attrs[count]; } return ret; } @@ -925,8 +945,6 @@ void pci_disable_msi(struct pci_dev *dev) pci_msi_shutdown(dev); free_msi_irqs(dev); - kset_unregister(dev->msi_kset); - dev->msi_kset = NULL; } EXPORT_SYMBOL(pci_disable_msi); @@ -1023,8 +1041,6 @@ void pci_disable_msix(struct pci_dev *dev) pci_msix_shutdown(dev); free_msi_irqs(dev); - kset_unregister(dev->msi_kset); - dev->msi_kset = NULL; } EXPORT_SYMBOL(pci_disable_msix); diff --git a/include/linux/pci.h b/include/linux/pci.h index 1084a15175e0..36a5b1828f91 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -351,7 +351,7 @@ struct pci_dev { struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ #ifdef CONFIG_PCI_MSI struct list_head msi_list; - struct kset *msi_kset; + const struct attribute_group **msi_irq_groups; #endif struct pci_vpd *vpd; #ifdef CONFIG_PCI_ATS -- cgit v1.2.3-59-g8ed1b From 8e1a28e8e6797449dfdfa4739002d1e5939355a8 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Thu, 19 Dec 2013 21:20:12 +0200 Subject: net/mlx4_core: Expose physical port id as PF/VF capability Add the infrastructure needed to support ndo_get_phys_port_id which allows users to identify to which physical port a net-device is connected to by reading a unique port id. This will work for VFs and PFs. The driver uses a new device capability - phys_port_id, The PF driver reads the port phys_port_id from Firmware and stores it. The VF driver reads the port phys_port_id from the PF using QUERY_FUNC_CAP command. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 45 +++++++++++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/fw.h | 1 + drivers/net/ethernet/mellanox/mlx4/main.c | 5 ++++ include/linux/mlx4/device.h | 2 ++ 4 files changed, 53 insertions(+) (limited to 'include/linux') diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index bfe91aebea8e..27a84342525f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -214,6 +214,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, #define QUERY_FUNC_CAP_QP0_PROXY 0x14 #define QUERY_FUNC_CAP_QP1_TUNNEL 0x18 #define QUERY_FUNC_CAP_QP1_PROXY 0x1c +#define QUERY_FUNC_CAP_PHYS_PORT_ID 0x28 #define QUERY_FUNC_CAP_FLAGS1_FORCE_MAC 0x40 #define QUERY_FUNC_CAP_FLAGS1_FORCE_VLAN 0x80 @@ -242,6 +243,9 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, size += 2; MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP1_PROXY); + MLX4_PUT(outbox->buf, dev->caps.phys_port_id[vhcr->in_modifier], + QUERY_FUNC_CAP_PHYS_PORT_ID); + } else if (vhcr->op_modifier == 0) { /* enable rdma and ethernet interfaces, and new quota locations */ field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA | @@ -432,6 +436,10 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u32 gen_or_port, MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP1_PROXY); func_cap->qp1_proxy_qpn = size & 0xFFFFFF; + if (func_cap->flags1 & QUERY_FUNC_CAP_FLAGS1_NIC_INFO) + MLX4_GET(func_cap->phys_port_id, outbox, + QUERY_FUNC_CAP_PHYS_PORT_ID); + /* All other resources are allocated by the master, but we still report * 'num' and 'reserved' capabilities as follows: * - num remains the maximum resource index @@ -1712,6 +1720,43 @@ int mlx4_NOP(struct mlx4_dev *dev) return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100, MLX4_CMD_NATIVE); } +int mlx4_get_phys_port_id(struct mlx4_dev *dev) +{ + u8 port; + u32 *outbox; + struct mlx4_cmd_mailbox *mailbox; + u32 in_mod; + u32 guid_hi, guid_lo; + int err, ret = 0; +#define MOD_STAT_CFG_PORT_OFFSET 8 +#define MOD_STAT_CFG_GUID_H 0X14 +#define MOD_STAT_CFG_GUID_L 0X1c + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + outbox = mailbox->buf; + + for (port = 1; port <= dev->caps.num_ports; port++) { + in_mod = port << MOD_STAT_CFG_PORT_OFFSET; + err = mlx4_cmd_box(dev, 0, mailbox->dma, in_mod, 0x2, + MLX4_CMD_MOD_STAT_CFG, MLX4_CMD_TIME_CLASS_A, + MLX4_CMD_NATIVE); + if (err) { + mlx4_err(dev, "Fail to get port %d uplink guid\n", + port); + ret = err; + } else { + MLX4_GET(guid_hi, outbox, MOD_STAT_CFG_GUID_H); + MLX4_GET(guid_lo, outbox, MOD_STAT_CFG_GUID_L); + dev->caps.phys_port_id[port] = (u64)guid_lo | + (u64)guid_hi << 32; + } + } + mlx4_free_cmd_mailbox(dev, mailbox); + return ret; +} + #define MLX4_WOL_SETUP_MODE (5 << 28) int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port) { diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h index 9d952983b076..6811ee00ba7c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw.h @@ -141,6 +141,7 @@ struct mlx4_func_cap { u8 physical_port; u8 port_flags; u8 flags1; + u64 phys_port_id; }; struct mlx4_adapter { diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index b37478db9851..6b13a15b3306 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -606,6 +606,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev) dev->caps.qp1_tunnel[i - 1] = func_cap.qp1_tunnel_qpn; dev->caps.qp1_proxy[i - 1] = func_cap.qp1_proxy_qpn; dev->caps.port_mask[i] = dev->caps.port_type[i]; + dev->caps.phys_port_id[i] = func_cap.phys_port_id; if (mlx4_get_slave_pkey_gid_tbl_len(dev, i, &dev->caps.gid_table_len[i], &dev->caps.pkey_table_len[i])) @@ -1484,6 +1485,10 @@ static int mlx4_init_hca(struct mlx4_dev *dev) choose_steering_mode(dev, &dev_cap); + err = mlx4_get_phys_port_id(dev); + if (err) + mlx4_err(dev, "Fail to get physical port id\n"); + if (mlx4_is_master(dev)) mlx4_parav_master_pf_caps(dev); diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index 7d3a523160ba..294b7c58fe95 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -454,6 +454,7 @@ struct mlx4_caps { u32 userspace_caps; /* userspace must be aware of these */ u32 function_caps; /* VFs must be aware of these */ u16 hca_core_clock; + u64 phys_port_id[MLX4_MAX_PORTS + 1]; }; struct mlx4_buf_list { @@ -1113,6 +1114,7 @@ int mlx4_assign_eq(struct mlx4_dev *dev, char *name, struct cpu_rmap *rmap, int *vector); void mlx4_release_eq(struct mlx4_dev *dev, int vec); +int mlx4_get_phys_port_id(struct mlx4_dev *dev); int mlx4_wol_read(struct mlx4_dev *dev, u64 *config, int port); int mlx4_wol_write(struct mlx4_dev *dev, u64 config, int port); -- cgit v1.2.3-59-g8ed1b From 18be099badcfc4a12f058addc55c4270d5a8bec8 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 20 Dec 2013 01:39:52 +0300 Subject: sh_eth: add PHY IRQ to platform data Allow the platform code to pass PHY's IRQ to the driver. Print this IRQ along with the other PHY datails in sh_eth_phy_init(). Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 6 ++++-- include/linux/sh_eth.h | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 8601d0c638cc..9d8013f82019 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1685,8 +1685,8 @@ static int sh_eth_phy_init(struct net_device *ndev) return PTR_ERR(phydev); } - dev_info(&ndev->dev, "attached phy %i to driver %s\n", - phydev->addr, phydev->drv->name); + dev_info(&ndev->dev, "attached PHY %d (IRQ %d) to driver %s\n", + phydev->addr, phydev->irq, phydev->drv->name); mdp->phydev = phydev; @@ -2544,6 +2544,8 @@ static int sh_mdio_init(struct net_device *ndev, int id, for (i = 0; i < PHY_MAX_ADDR; i++) mdp->mii_bus->irq[i] = PHY_POLL; + if (pd->phy_irq > 0) + mdp->mii_bus->irq[pd->phy] = pd->phy_irq; /* register mdio bus */ ret = mdiobus_register(mdp->mii_bus); diff --git a/include/linux/sh_eth.h b/include/linux/sh_eth.h index 90b5e30c2f22..8c9131db2b25 100644 --- a/include/linux/sh_eth.h +++ b/include/linux/sh_eth.h @@ -8,6 +8,7 @@ enum {EDMAC_LITTLE_ENDIAN, EDMAC_BIG_ENDIAN}; struct sh_eth_plat_data { int phy; + int phy_irq; int edmac_endian; phy_interface_t phy_interface; void (*set_mdio_gate)(void *addr); -- cgit v1.2.3-59-g8ed1b From 8ec5db6b20c860ddd1311c794b38c98ce86ac7ae Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 16 Dec 2013 09:34:57 +0100 Subject: PCI/MSI: Return -ENOSYS for unimplemented interfaces, not -1 Suggested-by: Ben Hutchings Signed-off-by: Alexander Gordeev Signed-off-by: Bjorn Helgaas Reviewed-by: Tejun Heo --- include/linux/pci.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/pci.h b/include/linux/pci.h index 36a5b1828f91..3c95efd12f3c 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1156,13 +1156,13 @@ struct msix_entry { #ifndef CONFIG_PCI_MSI static inline int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec) { - return -1; + return -ENOSYS; } static inline int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec) { - return -1; + return -ENOSYS; } static inline void pci_msi_shutdown(struct pci_dev *dev) @@ -1177,7 +1177,7 @@ static inline int pci_msix_table_size(struct pci_dev *dev) static inline int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec) { - return -1; + return -ENOSYS; } static inline void pci_msix_shutdown(struct pci_dev *dev) -- cgit v1.2.3-59-g8ed1b From 52179dc9edc3b7a2b3bb01cbb1b6c96f6d05fc73 Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Mon, 16 Dec 2013 09:34:58 +0100 Subject: PCI/MSI: Make pci_enable_msi/msix() 'nvec' argument type as int Make pci_enable_msi_block(), pci_enable_msi_block_auto() and pci_enable_msix() consistent with regard to the type of 'nvec' argument. Signed-off-by: Alexander Gordeev Signed-off-by: Bjorn Helgaas Reviewed-by: Tejun Heo --- Documentation/PCI/MSI-HOWTO.txt | 2 +- drivers/pci/msi.c | 4 ++-- include/linux/pci.h | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt index a09178086c30..a4d174e95413 100644 --- a/Documentation/PCI/MSI-HOWTO.txt +++ b/Documentation/PCI/MSI-HOWTO.txt @@ -129,7 +129,7 @@ call to succeed. 4.2.3 pci_enable_msi_block_auto -int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *count) +int pci_enable_msi_block_auto(struct pci_dev *dev, int *count) This variation on pci_enable_msi() call allows a device driver to request the maximum possible number of MSIs. The MSI specification only allows diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index a581381e02f2..ce0d4eb91a22 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -855,7 +855,7 @@ static int pci_msi_check_device(struct pci_dev *dev, int nvec, int type) * updates the @dev's irq member to the lowest new interrupt number; the * other interrupt numbers allocated to this device are consecutive. */ -int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec) +int pci_enable_msi_block(struct pci_dev *dev, int nvec) { int status, maxvec; u16 msgctl; @@ -886,7 +886,7 @@ int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec) } EXPORT_SYMBOL(pci_enable_msi_block); -int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec) +int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec) { int ret, nvec; u16 msgctl; diff --git a/include/linux/pci.h b/include/linux/pci.h index 3c95efd12f3c..7c34c3913bcb 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1154,13 +1154,13 @@ struct msix_entry { #ifndef CONFIG_PCI_MSI -static inline int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec) +static inline int pci_enable_msi_block(struct pci_dev *dev, int nvec) { return -ENOSYS; } static inline int -pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec) +pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec) { return -ENOSYS; } @@ -1195,8 +1195,8 @@ static inline int pci_msi_enabled(void) return 0; } #else -int pci_enable_msi_block(struct pci_dev *dev, unsigned int nvec); -int pci_enable_msi_block_auto(struct pci_dev *dev, unsigned int *maxvec); +int pci_enable_msi_block(struct pci_dev *dev, int nvec); +int pci_enable_msi_block_auto(struct pci_dev *dev, int *maxvec); void pci_msi_shutdown(struct pci_dev *dev); void pci_disable_msi(struct pci_dev *dev); int pci_msix_table_size(struct pci_dev *dev); -- cgit v1.2.3-59-g8ed1b From c67d0f29262bf6f863ce74d0756618bbd9ba80fd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 6 Dec 2013 10:05:49 +0100 Subject: ARM: s3c24xx: get rid of custom This isolates the custom S3C24xx GPIO definition table to as this is used in a few different places in the kernel, removing the need to depend on the implicit inclusion of from and thus getting rid of a few nasty cross-dependencies. We also delete the nifty CONFIG_S3C24XX_GPIO_EXTRA stuff. The biggest this can ever be for the S3C24XX is CONFIG_S3C24XX_GPIO_EXTRA = 128, and then for CPU_S3C2443 or CPU_S3C2416 32*12 GPIOs are added, so 32*12+128 = 512 is the absolute roof value on this platform. So we set the size of ARCH_NR_GPIO to this and the GPIOs array will fit any S3C24XX platform, as per pattern from other archs. ChangeLog v2->v3: - Move the movement of the S3C64XX gpio.h file out of this patch and into the follow-up patch where it belongs. ChangeLog v1->v2: - Added an #ifdef ARCH_S3C24XX around the header inclusion in drivers/gpio/gpio-samsung.c as we would otherwise have colliding definitions when compiling S3C64XX. - Rename inclusion guard in the header file. Cc: Tomasz Figa Cc: Sylwester Nawrocki Cc: Ben Dooks Cc: linux-samsung-soc@vger.kernel.org Acked-by: Kukjin Kim Acked-by: Heiko Stuebner Tested-by: Heiko Stuebner Signed-off-by: Linus Walleij --- arch/arm/Kconfig | 3 +- arch/arm/mach-s3c24xx/Kconfig | 21 ---- arch/arm/mach-s3c24xx/common-smdk.c | 2 +- arch/arm/mach-s3c24xx/h1940-bluetooth.c | 1 + arch/arm/mach-s3c24xx/include/mach/gpio.h | 114 --------------------- arch/arm/mach-s3c24xx/mach-amlm5900.c | 1 + arch/arm/mach-s3c24xx/mach-anubis.c | 1 + arch/arm/mach-s3c24xx/mach-at2440evb.c | 1 + arch/arm/mach-s3c24xx/mach-bast.c | 1 + arch/arm/mach-s3c24xx/mach-gta02.c | 1 + arch/arm/mach-s3c24xx/mach-h1940.c | 1 + arch/arm/mach-s3c24xx/mach-jive.c | 1 + arch/arm/mach-s3c24xx/mach-mini2440.c | 1 + arch/arm/mach-s3c24xx/mach-n30.c | 1 + arch/arm/mach-s3c24xx/mach-nexcoder.c | 1 + arch/arm/mach-s3c24xx/mach-osiris.c | 1 + arch/arm/mach-s3c24xx/mach-qt2410.c | 1 + arch/arm/mach-s3c24xx/mach-rx1950.c | 1 + arch/arm/mach-s3c24xx/mach-rx3715.c | 1 + arch/arm/mach-s3c24xx/mach-smdk2413.c | 1 + arch/arm/mach-s3c24xx/mach-smdk2416.c | 1 + arch/arm/mach-s3c24xx/mach-vr1000.c | 1 + arch/arm/mach-s3c24xx/pm-s3c2410.c | 1 + arch/arm/mach-s3c24xx/pm.c | 1 + arch/arm/mach-s3c24xx/s3c2410.c | 1 + arch/arm/mach-s3c24xx/s3c2416.c | 1 + arch/arm/mach-s3c24xx/s3c2440.c | 1 + arch/arm/mach-s3c24xx/s3c2442.c | 1 + arch/arm/mach-s3c24xx/s3c2443.c | 1 + arch/arm/mach-s3c24xx/setup-i2c.c | 1 + arch/arm/mach-s3c24xx/setup-sdhci-gpio.c | 1 + arch/arm/mach-s3c24xx/setup-ts.c | 1 + arch/arm/mach-s3c24xx/simtec-usb.c | 1 + arch/arm/plat-samsung/pm-gpio.c | 3 + arch/arm/plat-samsung/setup-camif.c | 1 + drivers/gpio/gpio-samsung.c | 3 + drivers/mmc/host/s3cmci.c | 1 + include/linux/platform_data/gpio-samsung-s3c24xx.h | 106 +++++++++++++++++++ 38 files changed, 145 insertions(+), 138 deletions(-) delete mode 100644 arch/arm/mach-s3c24xx/include/mach/gpio.h create mode 100644 include/linux/platform_data/gpio-samsung-s3c24xx.h (limited to 'include/linux') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c1f1a7eee953..6a26bcb3a63a 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -710,7 +710,6 @@ config ARCH_S3C24XX select HAVE_S3C2410_WATCHDOG if WATCHDOG select HAVE_S3C_RTC if RTC_CLASS select MULTI_IRQ_HANDLER - select NEED_MACH_GPIO_H select NEED_MACH_IO_H select SAMSUNG_ATAGS help @@ -1593,7 +1592,7 @@ config ARM_PSCI config ARCH_NR_GPIO int default 1024 if ARCH_SHMOBILE || ARCH_TEGRA - default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || SOC_DRA7XX + default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || SOC_DRA7XX || ARCH_S3C24XX default 392 if ARCH_U8500 default 352 if ARCH_VT8500 default 288 if ARCH_SUNXI diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig index 8f1d327e0cd1..d876431d64c0 100644 --- a/arch/arm/mach-s3c24xx/Kconfig +++ b/arch/arm/mach-s3c24xx/Kconfig @@ -180,27 +180,6 @@ config CPU_LLSERIAL_S3C2440 Selected if there is an S3C2440 (or register compatible) serial low-level implementation needed -# gpio configurations - -config S3C24XX_GPIO_EXTRA - int - default 128 if S3C24XX_GPIO_EXTRA128 - default 64 if S3C24XX_GPIO_EXTRA64 - default 16 if ARCH_H1940 - default 0 - -config S3C24XX_GPIO_EXTRA64 - bool - help - Add an extra 64 gpio numbers to the available GPIO pool. This is - available for boards that need extra gpios for external devices. - -config S3C24XX_GPIO_EXTRA128 - bool - help - Add an extra 128 gpio numbers to the available GPIO pool. This is - available for boards that need extra gpios for external devices. - config S3C24XX_PLL bool "Support CPUfreq changing of PLL frequency (EXPERIMENTAL)" depends on ARM_S3C24XX_CPUFREQ diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c index 404444dd3840..0a84a9c9f429 100644 --- a/arch/arm/mach-s3c24xx/common-smdk.c +++ b/arch/arm/mach-s3c24xx/common-smdk.c @@ -38,7 +38,7 @@ #include #include - +#include #include #include diff --git a/arch/arm/mach-s3c24xx/h1940-bluetooth.c b/arch/arm/mach-s3c24xx/h1940-bluetooth.c index 5b98bfd1df43..f2b859f4c894 100644 --- a/arch/arm/mach-s3c24xx/h1940-bluetooth.c +++ b/arch/arm/mach-s3c24xx/h1940-bluetooth.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/include/mach/gpio.h b/arch/arm/mach-s3c24xx/include/mach/gpio.h deleted file mode 100644 index 14591563ca70..000000000000 --- a/arch/arm/mach-s3c24xx/include/mach/gpio.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * S3C2410 - GPIO lib support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -/* some boards require extra gpio capacity to support external - * devices that need GPIO. - */ - -#ifndef __MACH_GPIO_H -#define __MACH_GPIO_H __FILE__ - -#ifdef CONFIG_CPU_S3C244X -#define ARCH_NR_GPIOS (32 * 9 + CONFIG_S3C24XX_GPIO_EXTRA) -#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416) -#define ARCH_NR_GPIOS (32 * 12 + CONFIG_S3C24XX_GPIO_EXTRA) -#else -#define ARCH_NR_GPIOS (256 + CONFIG_S3C24XX_GPIO_EXTRA) -#endif - -/* - * GPIO sizes for various SoCs: - * - * 2410 2412 2440 2443 2416 - * 2442 - * ---- ---- ---- ---- ---- - * A 23 22 25 16 25 - * B 11 11 11 11 9 - * C 16 15 16 16 16 - * D 16 16 16 16 16 - * E 16 16 16 16 16 - * F 8 8 8 8 8 - * G 16 16 16 16 8 - * H 11 11 9 15 15 - * J -- -- 13 16 -- - * K -- -- -- -- 16 - * L -- -- -- 15 7 - * M -- -- -- 2 2 - */ - -/* GPIO bank sizes */ - -#define S3C2410_GPIO_A_NR (32) -#define S3C2410_GPIO_B_NR (32) -#define S3C2410_GPIO_C_NR (32) -#define S3C2410_GPIO_D_NR (32) -#define S3C2410_GPIO_E_NR (32) -#define S3C2410_GPIO_F_NR (32) -#define S3C2410_GPIO_G_NR (32) -#define S3C2410_GPIO_H_NR (32) -#define S3C2410_GPIO_J_NR (32) /* technically 16. */ -#define S3C2410_GPIO_K_NR (32) /* technically 16. */ -#define S3C2410_GPIO_L_NR (32) /* technically 15. */ -#define S3C2410_GPIO_M_NR (32) /* technically 2. */ - -#if CONFIG_S3C_GPIO_SPACE != 0 -#error CONFIG_S3C_GPIO_SPACE cannot be nonzero at the moment -#endif - -#define S3C2410_GPIO_NEXT(__gpio) \ - ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0) - -#ifndef __ASSEMBLY__ - -enum s3c_gpio_number { - S3C2410_GPIO_A_START = 0, - S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A), - S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B), - S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C), - S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D), - S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E), - S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F), - S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G), - S3C2410_GPIO_J_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_H), - S3C2410_GPIO_K_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_J), - S3C2410_GPIO_L_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_K), - S3C2410_GPIO_M_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_L), -}; - -#endif /* __ASSEMBLY__ */ - -/* S3C2410 GPIO number definitions. */ - -#define S3C2410_GPA(_nr) (S3C2410_GPIO_A_START + (_nr)) -#define S3C2410_GPB(_nr) (S3C2410_GPIO_B_START + (_nr)) -#define S3C2410_GPC(_nr) (S3C2410_GPIO_C_START + (_nr)) -#define S3C2410_GPD(_nr) (S3C2410_GPIO_D_START + (_nr)) -#define S3C2410_GPE(_nr) (S3C2410_GPIO_E_START + (_nr)) -#define S3C2410_GPF(_nr) (S3C2410_GPIO_F_START + (_nr)) -#define S3C2410_GPG(_nr) (S3C2410_GPIO_G_START + (_nr)) -#define S3C2410_GPH(_nr) (S3C2410_GPIO_H_START + (_nr)) -#define S3C2410_GPJ(_nr) (S3C2410_GPIO_J_START + (_nr)) -#define S3C2410_GPK(_nr) (S3C2410_GPIO_K_START + (_nr)) -#define S3C2410_GPL(_nr) (S3C2410_GPIO_L_START + (_nr)) -#define S3C2410_GPM(_nr) (S3C2410_GPIO_M_START + (_nr)) - -#include - -#ifdef CONFIG_CPU_S3C244X -#define S3C_GPIO_END (S3C2410_GPJ(0) + 32) -#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416) -#define S3C_GPIO_END (S3C2410_GPM(0) + 32) -#else -#define S3C_GPIO_END (S3C2410_GPH(0) + 32) -#endif - -#endif /* __MACH_GPIO_H */ diff --git a/arch/arm/mach-s3c24xx/mach-amlm5900.c b/arch/arm/mach-s3c24xx/mach-amlm5900.c index e27b5c91b3db..530e9a624466 100644 --- a/arch/arm/mach-s3c24xx/mach-amlm5900.c +++ b/arch/arm/mach-s3c24xx/mach-amlm5900.c @@ -54,6 +54,7 @@ #include #include +#include #include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c index c1fb6c37867f..b60a248c033a 100644 --- a/arch/arm/mach-s3c24xx/mach-anubis.c +++ b/arch/arm/mach-s3c24xx/mach-anubis.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c index 6dfeeb7ef469..74401196b429 100644 --- a/arch/arm/mach-s3c24xx/mach-at2440evb.c +++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c index 22d6ae926d91..47fe7af87129 100644 --- a/arch/arm/mach-s3c24xx/mach-bast.c +++ b/arch/arm/mach-s3c24xx/mach-bast.c @@ -35,6 +35,7 @@ #include #include #include +#include #include diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c index 13d8d073675a..c2c2ac78cea8 100644 --- a/arch/arm/mach-s3c24xx/mach-gta02.c +++ b/arch/arm/mach-s3c24xx/mach-gta02.c @@ -70,6 +70,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c index 952b6a040d1f..d25d8b18512c 100644 --- a/arch/arm/mach-s3c24xx/mach-h1940.c +++ b/arch/arm/mach-s3c24xx/mach-h1940.c @@ -46,6 +46,7 @@ #include #include #include +#include #include diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c index 43c23e220f5b..434dbf231773 100644 --- a/arch/arm/mach-s3c24xx/mach-jive.c +++ b/arch/arm/mach-s3c24xx/mach-jive.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c index 4a18d49a63e0..48af11fc15fd 100644 --- a/arch/arm/mach-s3c24xx/mach-mini2440.c +++ b/arch/arm/mach-s3c24xx/mach-mini2440.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-n30.c b/arch/arm/mach-s3c24xx/mach-n30.c index 2cb46c37c920..7fcb887f5289 100644 --- a/arch/arm/mach-s3c24xx/mach-n30.c +++ b/arch/arm/mach-s3c24xx/mach-n30.c @@ -42,6 +42,7 @@ #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-nexcoder.c b/arch/arm/mach-s3c24xx/mach-nexcoder.c index 01f4354206f9..0f27ac44db09 100644 --- a/arch/arm/mach-s3c24xx/mach-nexcoder.c +++ b/arch/arm/mach-s3c24xx/mach-nexcoder.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c index 58d6fbe5bf1f..040b16aff93d 100644 --- a/arch/arm/mach-s3c24xx/mach-osiris.c +++ b/arch/arm/mach-s3c24xx/mach-osiris.c @@ -33,6 +33,7 @@ #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c index f8feaeadb55a..96c3bc858710 100644 --- a/arch/arm/mach-s3c24xx/mach-qt2410.c +++ b/arch/arm/mach-s3c24xx/mach-qt2410.c @@ -54,6 +54,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c index 034b7fe45c49..d492fb938bbb 100644 --- a/arch/arm/mach-s3c24xx/mach-rx1950.c +++ b/arch/arm/mach-s3c24xx/mach-rx1950.c @@ -45,6 +45,7 @@ #include #include #include +#include #include diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c index 3bc6231d0a1f..319ed8033475 100644 --- a/arch/arm/mach-s3c24xx/mach-rx3715.c +++ b/arch/arm/mach-s3c24xx/mach-rx3715.c @@ -35,6 +35,7 @@ #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-smdk2413.c b/arch/arm/mach-s3c24xx/mach-smdk2413.c index c9d31ef28dd1..86e25012b0c1 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2413.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2413.c @@ -39,6 +39,7 @@ #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-smdk2416.c b/arch/arm/mach-s3c24xx/mach-smdk2416.c index f88e672ad1e4..0cc691d01d60 100644 --- a/arch/arm/mach-s3c24xx/mach-smdk2416.c +++ b/arch/arm/mach-s3c24xx/mach-smdk2416.c @@ -41,6 +41,7 @@ #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/mach-vr1000.c b/arch/arm/mach-s3c24xx/mach-vr1000.c index 42e7187fed60..86e7ffdca33f 100644 --- a/arch/arm/mach-s3c24xx/mach-vr1000.c +++ b/arch/arm/mach-s3c24xx/mach-vr1000.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/pm-s3c2410.c b/arch/arm/mach-s3c24xx/pm-s3c2410.c index 2d82c4f116cd..e4cd56e8b90b 100644 --- a/arch/arm/mach-s3c24xx/pm-s3c2410.c +++ b/arch/arm/mach-s3c24xx/pm-s3c2410.c @@ -28,6 +28,7 @@ #include #include #include +#include #include diff --git a/arch/arm/mach-s3c24xx/pm.c b/arch/arm/mach-s3c24xx/pm.c index caa5b7211380..2baa887b28d2 100644 --- a/arch/arm/mach-s3c24xx/pm.c +++ b/arch/arm/mach-s3c24xx/pm.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/s3c2410.c b/arch/arm/mach-s3c24xx/s3c2410.c index 34676d1d5fec..db22f748ce8d 100644 --- a/arch/arm/mach-s3c24xx/s3c2410.c +++ b/arch/arm/mach-s3c24xx/s3c2410.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/s3c2416.c b/arch/arm/mach-s3c24xx/s3c2416.c index 9ef3ccfbe196..cb77880029f7 100644 --- a/arch/arm/mach-s3c24xx/s3c2416.c +++ b/arch/arm/mach-s3c24xx/s3c2416.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/s3c2440.c b/arch/arm/mach-s3c24xx/s3c2440.c index 5f9d6569475d..22e5dbdcbe8d 100644 --- a/arch/arm/mach-s3c24xx/s3c2440.c +++ b/arch/arm/mach-s3c24xx/s3c2440.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/s3c2442.c b/arch/arm/mach-s3c24xx/s3c2442.c index 6819961f6b19..4ba093b4e495 100644 --- a/arch/arm/mach-s3c24xx/s3c2442.c +++ b/arch/arm/mach-s3c24xx/s3c2442.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/s3c2443.c b/arch/arm/mach-s3c24xx/s3c2443.c index b6c71918b25c..faa1086924c4 100644 --- a/arch/arm/mach-s3c24xx/s3c2443.c +++ b/arch/arm/mach-s3c24xx/s3c2443.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/setup-i2c.c b/arch/arm/mach-s3c24xx/setup-i2c.c index 7b4f33332d19..3d1fd5ce24e5 100644 --- a/arch/arm/mach-s3c24xx/setup-i2c.c +++ b/arch/arm/mach-s3c24xx/setup-i2c.c @@ -17,6 +17,7 @@ struct platform_device; #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/setup-sdhci-gpio.c b/arch/arm/mach-s3c24xx/setup-sdhci-gpio.c index f65cb3ef16ce..2835241f732a 100644 --- a/arch/arm/mach-s3c24xx/setup-sdhci-gpio.c +++ b/arch/arm/mach-s3c24xx/setup-sdhci-gpio.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c24xx/setup-ts.c b/arch/arm/mach-s3c24xx/setup-ts.c index 4e11affce3a8..1ea4056f6fdc 100644 --- a/arch/arm/mach-s3c24xx/setup-ts.c +++ b/arch/arm/mach-s3c24xx/setup-ts.c @@ -12,6 +12,7 @@ #include #include +#include struct platform_device; /* don't need the contents */ diff --git a/arch/arm/mach-s3c24xx/simtec-usb.c b/arch/arm/mach-s3c24xx/simtec-usb.c index 2ed2e32430dc..a007e5f16583 100644 --- a/arch/arm/mach-s3c24xx/simtec-usb.c +++ b/arch/arm/mach-s3c24xx/simtec-usb.c @@ -32,6 +32,7 @@ #include #include +#include #include #include "bast.h" diff --git a/arch/arm/plat-samsung/pm-gpio.c b/arch/arm/plat-samsung/pm-gpio.c index a8de3cfe2ee1..41fef6980230 100644 --- a/arch/arm/plat-samsung/pm-gpio.c +++ b/arch/arm/plat-samsung/pm-gpio.c @@ -19,6 +19,9 @@ #include #include +#ifdef CONFIG_ARCH_S3C24XX +#include +#endif #include #include diff --git a/arch/arm/plat-samsung/setup-camif.c b/arch/arm/plat-samsung/setup-camif.c index e01bf760af2c..70cf503c9a6b 100644 --- a/arch/arm/plat-samsung/setup-camif.c +++ b/arch/arm/plat-samsung/setup-camif.c @@ -9,6 +9,7 @@ */ #include +#include #include /* Number of camera port pins, without FIELD */ diff --git a/drivers/gpio/gpio-samsung.c b/drivers/gpio/gpio-samsung.c index 76e02b9460e6..268214c57799 100644 --- a/drivers/gpio/gpio-samsung.c +++ b/drivers/gpio/gpio-samsung.c @@ -27,6 +27,9 @@ #include #include #include +#ifdef CONFIG_ARCH_S3C24XX +#include +#endif #include diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index 2fce5ea5eb39..11ba3cbb0951 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -26,6 +26,7 @@ #include #include +#include #include "s3cmci.h" diff --git a/include/linux/platform_data/gpio-samsung-s3c24xx.h b/include/linux/platform_data/gpio-samsung-s3c24xx.h new file mode 100644 index 000000000000..5ce750c84a14 --- /dev/null +++ b/include/linux/platform_data/gpio-samsung-s3c24xx.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * + * S3C2410 - GPIO lib support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +/* some boards require extra gpio capacity to support external + * devices that need GPIO. + */ + +#ifndef GPIO_SAMSUNG_S3C24XX_H +#define GPIO_SAMSUNG_S3C24XX_H + +/* + * GPIO sizes for various SoCs: + * + * 2410 2412 2440 2443 2416 + * 2442 + * ---- ---- ---- ---- ---- + * A 23 22 25 16 25 + * B 11 11 11 11 9 + * C 16 15 16 16 16 + * D 16 16 16 16 16 + * E 16 16 16 16 16 + * F 8 8 8 8 8 + * G 16 16 16 16 8 + * H 11 11 9 15 15 + * J -- -- 13 16 -- + * K -- -- -- -- 16 + * L -- -- -- 15 7 + * M -- -- -- 2 2 + */ + +/* GPIO bank sizes */ + +#define S3C2410_GPIO_A_NR (32) +#define S3C2410_GPIO_B_NR (32) +#define S3C2410_GPIO_C_NR (32) +#define S3C2410_GPIO_D_NR (32) +#define S3C2410_GPIO_E_NR (32) +#define S3C2410_GPIO_F_NR (32) +#define S3C2410_GPIO_G_NR (32) +#define S3C2410_GPIO_H_NR (32) +#define S3C2410_GPIO_J_NR (32) /* technically 16. */ +#define S3C2410_GPIO_K_NR (32) /* technically 16. */ +#define S3C2410_GPIO_L_NR (32) /* technically 15. */ +#define S3C2410_GPIO_M_NR (32) /* technically 2. */ + +#if CONFIG_S3C_GPIO_SPACE != 0 +#error CONFIG_S3C_GPIO_SPACE cannot be nonzero at the moment +#endif + +#define S3C2410_GPIO_NEXT(__gpio) \ + ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 0) + +#ifndef __ASSEMBLY__ + +enum s3c_gpio_number { + S3C2410_GPIO_A_START = 0, + S3C2410_GPIO_B_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_A), + S3C2410_GPIO_C_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_B), + S3C2410_GPIO_D_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_C), + S3C2410_GPIO_E_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_D), + S3C2410_GPIO_F_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_E), + S3C2410_GPIO_G_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_F), + S3C2410_GPIO_H_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_G), + S3C2410_GPIO_J_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_H), + S3C2410_GPIO_K_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_J), + S3C2410_GPIO_L_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_K), + S3C2410_GPIO_M_START = S3C2410_GPIO_NEXT(S3C2410_GPIO_L), +}; + +#endif /* __ASSEMBLY__ */ + +/* S3C2410 GPIO number definitions. */ + +#define S3C2410_GPA(_nr) (S3C2410_GPIO_A_START + (_nr)) +#define S3C2410_GPB(_nr) (S3C2410_GPIO_B_START + (_nr)) +#define S3C2410_GPC(_nr) (S3C2410_GPIO_C_START + (_nr)) +#define S3C2410_GPD(_nr) (S3C2410_GPIO_D_START + (_nr)) +#define S3C2410_GPE(_nr) (S3C2410_GPIO_E_START + (_nr)) +#define S3C2410_GPF(_nr) (S3C2410_GPIO_F_START + (_nr)) +#define S3C2410_GPG(_nr) (S3C2410_GPIO_G_START + (_nr)) +#define S3C2410_GPH(_nr) (S3C2410_GPIO_H_START + (_nr)) +#define S3C2410_GPJ(_nr) (S3C2410_GPIO_J_START + (_nr)) +#define S3C2410_GPK(_nr) (S3C2410_GPIO_K_START + (_nr)) +#define S3C2410_GPL(_nr) (S3C2410_GPIO_L_START + (_nr)) +#define S3C2410_GPM(_nr) (S3C2410_GPIO_M_START + (_nr)) + +#include + +#ifdef CONFIG_CPU_S3C244X +#define S3C_GPIO_END (S3C2410_GPJ(0) + 32) +#elif defined(CONFIG_CPU_S3C2443) || defined(CONFIG_CPU_S3C2416) +#define S3C_GPIO_END (S3C2410_GPM(0) + 32) +#else +#define S3C_GPIO_END (S3C2410_GPH(0) + 32) +#endif + +#endif /* GPIO_SAMSUNG_S3C24XX_H */ -- cgit v1.2.3-59-g8ed1b From 41c3548e6da67786bcaf8ee7b406f6f85ddd816b Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 6 Dec 2013 12:46:27 +0100 Subject: ARM: s3c64xx: get rid of custom This isolates the custom S3C64xx GPIO definition table to as this is used in a few different places in the kernel, removing the need to depend on the implicit inclusion of from and thus getting rid of a few nasty cross-dependencies. Also delete the CONFIG_SAMSUNG_GPIO_EXTRA stuff. Instead roof the number of GPIOs for this platform: First sum up all the GPIO banks from A to Q: 187 GPIOs. Add the 16 "board GPIOs" and the roof for SAMSUNG_GPIO_EXTRA, 128, so in total maximum 187+16+128 = 331 GPIOs, so let's take the same roof as for S3C24XX: 512. This way we can do away with the GPIO calculation macros for GPIO_BOARD_START, BOARD_NR_GPIOS and the definition of ARCH_NR_GPIOS. Cc: Mark Brown [on Mini6410 board] Tested-by: Tomasz Figa [for changes in mach-s3c64xx] Acked-by: Tomasz Figa Tested-by: Mark Brown Acked-by: Kukjin Kim Signed-off-by: Linus Walleij --- arch/arm/Kconfig | 3 +- arch/arm/mach-s3c64xx/Kconfig | 3 - arch/arm/mach-s3c64xx/common.c | 1 + arch/arm/mach-s3c64xx/crag6410.h | 2 +- arch/arm/mach-s3c64xx/dev-audio.c | 1 + arch/arm/mach-s3c64xx/include/mach/gpio.h | 93 --------------------- arch/arm/mach-s3c64xx/mach-anw6410.c | 1 + arch/arm/mach-s3c64xx/mach-crag6410.c | 1 + arch/arm/mach-s3c64xx/mach-hmt.c | 1 + arch/arm/mach-s3c64xx/mach-mini6410.c | 1 + arch/arm/mach-s3c64xx/mach-real6410.c | 1 + arch/arm/mach-s3c64xx/mach-smartq.c | 1 + arch/arm/mach-s3c64xx/mach-smartq5.c | 1 + arch/arm/mach-s3c64xx/mach-smartq7.c | 1 + arch/arm/mach-s3c64xx/mach-smdk6400.c | 1 + arch/arm/mach-s3c64xx/mach-smdk6410.c | 1 + arch/arm/mach-s3c64xx/pm.c | 1 + arch/arm/mach-s3c64xx/setup-fb-24bpp.c | 1 + arch/arm/mach-s3c64xx/setup-i2c0.c | 1 + arch/arm/mach-s3c64xx/setup-i2c1.c | 1 + arch/arm/mach-s3c64xx/setup-ide.c | 1 + arch/arm/mach-s3c64xx/setup-keypad.c | 1 + arch/arm/mach-s3c64xx/setup-sdhci-gpio.c | 1 + arch/arm/mach-s3c64xx/setup-spi.c | 1 + arch/arm/plat-samsung/pm-gpio.c | 3 + drivers/gpio/gpio-samsung.c | 3 + include/linux/platform_data/gpio-samsung-s3c64xx.h | 94 ++++++++++++++++++++++ 27 files changed, 122 insertions(+), 99 deletions(-) delete mode 100644 arch/arm/mach-s3c64xx/include/mach/gpio.h create mode 100644 include/linux/platform_data/gpio-samsung-s3c64xx.h (limited to 'include/linux') diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 6a26bcb3a63a..103437986684 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -732,7 +732,6 @@ config ARCH_S3C64XX select HAVE_S3C2410_I2C if I2C select HAVE_S3C2410_WATCHDOG if WATCHDOG select HAVE_TCM - select NEED_MACH_GPIO_H select NO_IOPORT select PLAT_SAMSUNG select PM_GENERIC_DOMAINS @@ -1592,7 +1591,7 @@ config ARM_PSCI config ARCH_NR_GPIO int default 1024 if ARCH_SHMOBILE || ARCH_TEGRA - default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || SOC_DRA7XX || ARCH_S3C24XX + default 512 if ARCH_EXYNOS || ARCH_KEYSTONE || SOC_OMAP5 || SOC_DRA7XX || ARCH_S3C24XX || ARCH_S3C64XX default 392 if ARCH_U8500 default 352 if ARCH_VT8500 default 288 if ARCH_SUNXI diff --git a/arch/arm/mach-s3c64xx/Kconfig b/arch/arm/mach-s3c64xx/Kconfig index 2cb8dc55b50e..175f01501129 100644 --- a/arch/arm/mach-s3c64xx/Kconfig +++ b/arch/arm/mach-s3c64xx/Kconfig @@ -192,7 +192,6 @@ config SMDK6410_WM1190_EV1 select MFD_WM8350_I2C select REGULATOR select REGULATOR_WM8350 - select SAMSUNG_GPIO_EXTRA64 help The Wolfson Microelectronics 1190-EV1 is a WM835x based PMIC and audio daughtercard for the Samsung SMDK6410 reference @@ -208,7 +207,6 @@ config SMDK6410_WM1192_EV1 select MFD_WM831X_I2C select REGULATOR select REGULATOR_WM831X - select SAMSUNG_GPIO_EXTRA64 help The Wolfson Microelectronics 1192-EV1 is a WM831x based PMIC daughtercard for the Samsung SMDK6410 reference platform. @@ -294,7 +292,6 @@ config MACH_WLF_CRAGG_6410 select SAMSUNG_DEV_ADC select SAMSUNG_DEV_KEYPAD select SAMSUNG_DEV_PWM - select SAMSUNG_GPIO_EXTRA128 help Machine support for the Wolfson Cragganmore S3C6410 variant. diff --git a/arch/arm/mach-s3c64xx/common.c b/arch/arm/mach-s3c64xx/common.c index 7a3ce4c39e5f..64edda37bde3 100644 --- a/arch/arm/mach-s3c64xx/common.c +++ b/arch/arm/mach-s3c64xx/common.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-s3c64xx/crag6410.h b/arch/arm/mach-s3c64xx/crag6410.h index 4c3c9994fc2c..9ef20b8fd36f 100644 --- a/arch/arm/mach-s3c64xx/crag6410.h +++ b/arch/arm/mach-s3c64xx/crag6410.h @@ -11,7 +11,7 @@ #ifndef MACH_CRAG6410_H #define MACH_CRAG6410_H -#include +#include #define GLENFARCLAS_PMIC_IRQ_BASE IRQ_BOARD_START diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c index e367e87bbc29..6f58c80235dc 100644 --- a/arch/arm/mach-s3c64xx/dev-audio.c +++ b/arch/arm/mach-s3c64xx/dev-audio.c @@ -21,6 +21,7 @@ #include #include +#include #include static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev) diff --git a/arch/arm/mach-s3c64xx/include/mach/gpio.h b/arch/arm/mach-s3c64xx/include/mach/gpio.h deleted file mode 100644 index 8b540c42d5dd..000000000000 --- a/arch/arm/mach-s3c64xx/include/mach/gpio.h +++ /dev/null @@ -1,93 +0,0 @@ -/* arch/arm/mach-s3c6400/include/mach/gpio.h - * - * Copyright 2008 Openmoko, Inc. - * Copyright 2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * S3C6400 - GPIO lib support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -/* GPIO bank sizes */ -#define S3C64XX_GPIO_A_NR (8) -#define S3C64XX_GPIO_B_NR (7) -#define S3C64XX_GPIO_C_NR (8) -#define S3C64XX_GPIO_D_NR (5) -#define S3C64XX_GPIO_E_NR (5) -#define S3C64XX_GPIO_F_NR (16) -#define S3C64XX_GPIO_G_NR (7) -#define S3C64XX_GPIO_H_NR (10) -#define S3C64XX_GPIO_I_NR (16) -#define S3C64XX_GPIO_J_NR (12) -#define S3C64XX_GPIO_K_NR (16) -#define S3C64XX_GPIO_L_NR (15) -#define S3C64XX_GPIO_M_NR (6) -#define S3C64XX_GPIO_N_NR (16) -#define S3C64XX_GPIO_O_NR (16) -#define S3C64XX_GPIO_P_NR (15) -#define S3C64XX_GPIO_Q_NR (9) - -/* GPIO bank numbes */ - -/* CONFIG_S3C_GPIO_SPACE allows the user to select extra - * space for debugging purposes so that any accidental - * change from one gpio bank to another can be caught. -*/ - -#define S3C64XX_GPIO_NEXT(__gpio) \ - ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1) - -enum s3c_gpio_number { - S3C64XX_GPIO_A_START = 0, - S3C64XX_GPIO_B_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_A), - S3C64XX_GPIO_C_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_B), - S3C64XX_GPIO_D_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_C), - S3C64XX_GPIO_E_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_D), - S3C64XX_GPIO_F_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_E), - S3C64XX_GPIO_G_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_F), - S3C64XX_GPIO_H_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_G), - S3C64XX_GPIO_I_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_H), - S3C64XX_GPIO_J_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_I), - S3C64XX_GPIO_K_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_J), - S3C64XX_GPIO_L_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_K), - S3C64XX_GPIO_M_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_L), - S3C64XX_GPIO_N_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_M), - S3C64XX_GPIO_O_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_N), - S3C64XX_GPIO_P_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_O), - S3C64XX_GPIO_Q_START = S3C64XX_GPIO_NEXT(S3C64XX_GPIO_P), -}; - -/* S3C64XX GPIO number definitions. */ - -#define S3C64XX_GPA(_nr) (S3C64XX_GPIO_A_START + (_nr)) -#define S3C64XX_GPB(_nr) (S3C64XX_GPIO_B_START + (_nr)) -#define S3C64XX_GPC(_nr) (S3C64XX_GPIO_C_START + (_nr)) -#define S3C64XX_GPD(_nr) (S3C64XX_GPIO_D_START + (_nr)) -#define S3C64XX_GPE(_nr) (S3C64XX_GPIO_E_START + (_nr)) -#define S3C64XX_GPF(_nr) (S3C64XX_GPIO_F_START + (_nr)) -#define S3C64XX_GPG(_nr) (S3C64XX_GPIO_G_START + (_nr)) -#define S3C64XX_GPH(_nr) (S3C64XX_GPIO_H_START + (_nr)) -#define S3C64XX_GPI(_nr) (S3C64XX_GPIO_I_START + (_nr)) -#define S3C64XX_GPJ(_nr) (S3C64XX_GPIO_J_START + (_nr)) -#define S3C64XX_GPK(_nr) (S3C64XX_GPIO_K_START + (_nr)) -#define S3C64XX_GPL(_nr) (S3C64XX_GPIO_L_START + (_nr)) -#define S3C64XX_GPM(_nr) (S3C64XX_GPIO_M_START + (_nr)) -#define S3C64XX_GPN(_nr) (S3C64XX_GPIO_N_START + (_nr)) -#define S3C64XX_GPO(_nr) (S3C64XX_GPIO_O_START + (_nr)) -#define S3C64XX_GPP(_nr) (S3C64XX_GPIO_P_START + (_nr)) -#define S3C64XX_GPQ(_nr) (S3C64XX_GPIO_Q_START + (_nr)) - -/* the end of the S3C64XX specific gpios */ -#define S3C64XX_GPIO_END (S3C64XX_GPQ(S3C64XX_GPIO_Q_NR) + 1) -#define S3C_GPIO_END S3C64XX_GPIO_END - -/* define the number of gpios we need to the one after the GPQ() range */ -#define GPIO_BOARD_START (S3C64XX_GPQ(S3C64XX_GPIO_Q_NR) + 1) - -#define BOARD_NR_GPIOS (16 + CONFIG_SAMSUNG_GPIO_EXTRA) - -#define ARCH_NR_GPIOS (GPIO_BOARD_START + BOARD_NR_GPIOS) diff --git a/arch/arm/mach-s3c64xx/mach-anw6410.c b/arch/arm/mach-s3c64xx/mach-anw6410.c index d266dd5f7060..546f45b59ea1 100644 --- a/arch/arm/mach-s3c64xx/mach-anw6410.c +++ b/arch/arm/mach-s3c64xx/mach-anw6410.c @@ -43,6 +43,7 @@ #include #include +#include #include #include diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c index 758e31b26550..7b913595e4ee 100644 --- a/arch/arm/mach-s3c64xx/mach-crag6410.c +++ b/arch/arm/mach-s3c64xx/mach-crag6410.c @@ -32,6 +32,7 @@ #include #include +#include #include