Revision a99b646afa8a02571ea298bedca6592d818229cd authored by dingtianhong on 15 August 2017, 03:23:23 UTC, committed by David S. Miller on 15 August 2017, 05:14:50 UTC
When bit4 is set in the PCIe Device Control register, it indicates
whether the device is permitted to use relaxed ordering.
On some platforms using relaxed ordering can have performance issues or
due to erratum can cause data-corruption. In such cases devices must avoid
using relaxed ordering.

The patch adds a new flag PCI_DEV_FLAGS_NO_RELAXED_ORDERING to indicate that
Relaxed Ordering (RO) attribute should not be used for Transaction Layer
Packets (TLP) targeted towards these affected root complexes.

This patch checks if there is any node in the hierarchy that indicates that
using relaxed ordering is not safe. In such cases the patch turns off the
relaxed ordering by clearing the capability for this device.

Signed-off-by: Casey Leedom <leedom@chelsio.com>
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
Acked-by: Ashok Raj <ashok.raj@intel.com>
Acked-by: Alexander Duyck <alexander.h.duyck@intel.com>
Acked-by: Casey Leedom <leedom@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 59a361b
Raw File
packets-buffer.c
/*
 * helpers for managing a buffer for many packets
 *
 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
 * Licensed under the terms of the GNU General Public License, version 2.
 */

#include <linux/firewire.h>
#include <linux/export.h>
#include <linux/slab.h>
#include "packets-buffer.h"

/**
 * iso_packets_buffer_init - allocates the memory for packets
 * @b: the buffer structure to initialize
 * @unit: the device at the other end of the stream
 * @count: the number of packets
 * @packet_size: the (maximum) size of a packet, in bytes
 * @direction: %DMA_TO_DEVICE or %DMA_FROM_DEVICE
 */
int iso_packets_buffer_init(struct iso_packets_buffer *b, struct fw_unit *unit,
			    unsigned int count, unsigned int packet_size,
			    enum dma_data_direction direction)
{
	unsigned int packets_per_page, pages;
	unsigned int i, page_index, offset_in_page;
	void *p;
	int err;

	b->packets = kmalloc(count * sizeof(*b->packets), GFP_KERNEL);
	if (!b->packets) {
		err = -ENOMEM;
		goto error;
	}

	packet_size = L1_CACHE_ALIGN(packet_size);
	packets_per_page = PAGE_SIZE / packet_size;
	if (WARN_ON(!packets_per_page)) {
		err = -EINVAL;
		goto error;
	}
	pages = DIV_ROUND_UP(count, packets_per_page);

	err = fw_iso_buffer_init(&b->iso_buffer, fw_parent_device(unit)->card,
				 pages, direction);
	if (err < 0)
		goto err_packets;

	for (i = 0; i < count; ++i) {
		page_index = i / packets_per_page;
		p = page_address(b->iso_buffer.pages[page_index]);
		offset_in_page = (i % packets_per_page) * packet_size;
		b->packets[i].buffer = p + offset_in_page;
		b->packets[i].offset = page_index * PAGE_SIZE + offset_in_page;
	}

	return 0;

err_packets:
	kfree(b->packets);
error:
	return err;
}
EXPORT_SYMBOL(iso_packets_buffer_init);

/**
 * iso_packets_buffer_destroy - frees packet buffer resources
 * @b: the buffer structure to free
 * @unit: the device at the other end of the stream
 */
void iso_packets_buffer_destroy(struct iso_packets_buffer *b,
				struct fw_unit *unit)
{
	fw_iso_buffer_destroy(&b->iso_buffer, fw_parent_device(unit)->card);
	kfree(b->packets);
}
EXPORT_SYMBOL(iso_packets_buffer_destroy);
back to top