Commit 406fb9eb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'firewire-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394

Pull firewire updates from Takashi Sakamoto:
 "This consist of three parts; UAPI update, OHCI driver update, and
  several bug fixes.

  Firstly, the 1394 OHCI specification defines method to retrieve
  hardware time stamps for asynchronous communication, which was
  previously unavailable in user space. This adds new events to the
  UAPI, allowing applications to retrieve the time when asynchronous
  packet are received and sent. The new events are tested in the
  bleeding edge of libhinawa and look to work well. The new version of
  libhinawa will be released after current merge window is closed:

    https://git.kernel.org/pub/scm/libs/ieee1394/libhinawa.git/

  Secondly, the FireWire stack includes a PCM device driver for 1394
  OHCI hardware, This change modernizes the driver by managed resource
  (devres) framework.

  Lastly, bug fixes for firewire-net and firewire-core"

* tag 'firewire-6.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394: (25 commits)
  firewire: net: fix use after free in fwnet_finish_incoming_packet()
  firewire: core: obsolete usage of GFP_ATOMIC at building node tree
  firewire: ohci: release buffer for AR req/resp contexts when managed resource is released
  firewire: ohci: use devres for content of configuration ROM
  firewire: ohci: use devres for IT, IR, AT/receive, and AT/request contexts
  firewire: ohci: use devres for list of isochronous contexts
  firewire: ohci: use devres for requested IRQ
  firewire: ohci: use devres for misc DMA buffer
  firewire: ohci: use devres for MMIO region mapping
  firewire: ohci: use devres for PCI-related resources
  firewire: ohci: use devres for memory object of ohci structure
  firewire: fix warnings to generate UAPI documentation
  firewire: fix build failure due to missing module license
  firewire: cdev: implement new event relevant to phy packet with time stamp
  firewire: cdev: add new event to notify phy packet with time stamp
  firewire: cdev: code refactoring to dispatch event for phy packet
  firewire: cdev: implement new event to notify response subaction with time stamp
  firewire: cdev: add new event to notify response subaction with time stamp
  firewire: cdev: code refactoring to operate event of response
  firewire: core: implement variations to send request and wait for response with time stamp
  ...
parents f1962207 3ff25675
CONFIG_KUNIT=y
CONFIG_PCI=y
CONFIG_FIREWIRE=y
CONFIG_FIREWIRE_KUNIT_UAPI_TEST=y
......@@ -18,6 +18,22 @@ config FIREWIRE
To compile this driver as a module, say M here: the module will be
called firewire-core.
config FIREWIRE_KUNIT_UAPI_TEST
tristate "KUnit tests for layout of structure in UAPI" if !KUNIT_ALL_TESTS
depends on FIREWIRE && KUNIT
default KUNIT_ALL_TESTS
help
This builds the KUnit tests whether structures exposed to user
space have expected layout.
KUnit tests run during boot and output the results to the debug
log in TAP format (https://testanything.org/). Only useful for
kernel devs running KUnit test harness and are not for inclusion
into a production build.
For more information on KUnit and unit tests in general, refer
to the KUnit documentation in Documentation/dev-tools/kunit/.
config FIREWIRE_OHCI
tristate "OHCI-1394 controllers"
depends on PCI && FIREWIRE && MMU
......
......@@ -15,3 +15,6 @@ obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o
obj-$(CONFIG_FIREWIRE_NET) += firewire-net.o
obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o
obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o
firewire-uapi-test-objs += uapi-test.o
obj-$(CONFIG_FIREWIRE_KUNIT_UAPI_TEST) += firewire-uapi-test.o
This diff is collapsed.
......@@ -1211,7 +1211,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event)
* without actually having a link.
*/
create:
device = kzalloc(sizeof(*device), GFP_ATOMIC);
device = kzalloc(sizeof(*device), GFP_KERNEL);
if (device == NULL)
break;
......
......@@ -101,7 +101,7 @@ static struct fw_node *fw_node_create(u32 sid, int port_count, int color)
{
struct fw_node *node;
node = kzalloc(struct_size(node, ports, port_count), GFP_ATOMIC);
node = kzalloc(struct_size(node, ports, port_count), GFP_KERNEL);
if (node == NULL)
return NULL;
......
......@@ -70,8 +70,8 @@ static int try_cancel_split_timeout(struct fw_transaction *t)
return 1;
}
static int close_transaction(struct fw_transaction *transaction,
struct fw_card *card, int rcode)
static int close_transaction(struct fw_transaction *transaction, struct fw_card *card, int rcode,
u32 response_tstamp)
{
struct fw_transaction *t = NULL, *iter;
unsigned long flags;
......@@ -92,7 +92,12 @@ static int close_transaction(struct fw_transaction *transaction,
spin_unlock_irqrestore(&card->lock, flags);
if (t) {
t->callback(card, rcode, NULL, 0, t->callback_data);
if (!t->with_tstamp) {
t->callback.without_tstamp(card, rcode, NULL, 0, t->callback_data);
} else {
t->callback.with_tstamp(card, rcode, t->packet.timestamp, response_tstamp,
NULL, 0, t->callback_data);
}
return 0;
}
......@@ -107,6 +112,8 @@ static int close_transaction(struct fw_transaction *transaction,
int fw_cancel_transaction(struct fw_card *card,
struct fw_transaction *transaction)
{
u32 tstamp;
/*
* Cancel the packet transmission if it's still queued. That
* will call the packet transmission callback which cancels
......@@ -121,7 +128,17 @@ int fw_cancel_transaction(struct fw_card *card,
* if the transaction is still pending and remove it in that case.
*/
return close_transaction(transaction, card, RCODE_CANCELLED);
if (transaction->packet.ack == 0) {
// The timestamp is reused since it was just read now.
tstamp = transaction->packet.timestamp;
} else {
u32 curr_cycle_time = 0;
(void)fw_card_read_cycle_time(card, &curr_cycle_time);
tstamp = cycle_time_to_ohci_tstamp(curr_cycle_time);
}
return close_transaction(transaction, card, RCODE_CANCELLED, tstamp);
}
EXPORT_SYMBOL(fw_cancel_transaction);
......@@ -140,7 +157,12 @@ static void split_transaction_timeout_callback(struct timer_list *timer)
card->tlabel_mask &= ~(1ULL << t->tlabel);
spin_unlock_irqrestore(&card->lock, flags);
t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
if (!t->with_tstamp) {
t->callback.without_tstamp(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
} else {
t->callback.with_tstamp(card, RCODE_CANCELLED, t->packet.timestamp,
t->split_timeout_cycle, NULL, 0, t->callback_data);
}
}
static void start_split_transaction_timeout(struct fw_transaction *t,
......@@ -162,6 +184,8 @@ static void start_split_transaction_timeout(struct fw_transaction *t,
spin_unlock_irqrestore(&card->lock, flags);
}
static u32 compute_split_timeout_timestamp(struct fw_card *card, u32 request_timestamp);
static void transmit_complete_callback(struct fw_packet *packet,
struct fw_card *card, int status)
{
......@@ -170,28 +194,32 @@ static void transmit_complete_callback(struct fw_packet *packet,
switch (status) {
case ACK_COMPLETE:
close_transaction(t, card, RCODE_COMPLETE);
close_transaction(t, card, RCODE_COMPLETE, packet->timestamp);
break;
case ACK_PENDING:
{
t->split_timeout_cycle =
compute_split_timeout_timestamp(card, packet->timestamp) & 0xffff;
start_split_transaction_timeout(t, card);
break;
}
case ACK_BUSY_X:
case ACK_BUSY_A:
case ACK_BUSY_B:
close_transaction(t, card, RCODE_BUSY);
close_transaction(t, card, RCODE_BUSY, packet->timestamp);
break;
case ACK_DATA_ERROR:
close_transaction(t, card, RCODE_DATA_ERROR);
close_transaction(t, card, RCODE_DATA_ERROR, packet->timestamp);
break;
case ACK_TYPE_ERROR:
close_transaction(t, card, RCODE_TYPE_ERROR);
close_transaction(t, card, RCODE_TYPE_ERROR, packet->timestamp);
break;
default:
/*
* In this case the ack is really a juju specific
* rcode, so just forward that to the callback.
*/
close_transaction(t, card, status);
close_transaction(t, card, status, packet->timestamp);
break;
}
}
......@@ -288,7 +316,8 @@ static int allocate_tlabel(struct fw_card *card)
}
/**
* fw_send_request() - submit a request packet for transmission
* __fw_send_request() - submit a request packet for transmission to generate callback for response
* subaction with or without time stamp.
* @card: interface to send the request at
* @t: transaction instance to which the request belongs
* @tcode: transaction code
......@@ -298,7 +327,9 @@ static int allocate_tlabel(struct fw_card *card)
* @offset: 48bit wide offset into destination's address space
* @payload: data payload for the request subaction
* @length: length of the payload, in bytes
* @callback: function to be called when the transaction is completed
* @callback: union of two functions whether to receive time stamp or not for response
* subaction.
* @with_tstamp: Whether to receive time stamp or not for response subaction.
* @callback_data: data to be passed to the transaction completion callback
*
* Submit a request packet into the asynchronous request transmission queue.
......@@ -335,10 +366,10 @@ static int allocate_tlabel(struct fw_card *card)
* transaction completion and hence execution of @callback may happen even
* before fw_send_request() returns.
*/
void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
int destination_id, int generation, int speed,
unsigned long long offset, void *payload, size_t length,
fw_transaction_callback_t callback, void *callback_data)
void __fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
int destination_id, int generation, int speed, unsigned long long offset,
void *payload, size_t length, union fw_transaction_callback callback,
bool with_tstamp, void *callback_data)
{
unsigned long flags;
int tlabel;
......@@ -353,7 +384,19 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
tlabel = allocate_tlabel(card);
if (tlabel < 0) {
spin_unlock_irqrestore(&card->lock, flags);
callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
if (!with_tstamp) {
callback.without_tstamp(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
} else {
// Timestamping on behalf of hardware.
u32 curr_cycle_time = 0;
u32 tstamp;
(void)fw_card_read_cycle_time(card, &curr_cycle_time);
tstamp = cycle_time_to_ohci_tstamp(curr_cycle_time);
callback.with_tstamp(card, RCODE_SEND_ERROR, tstamp, tstamp, NULL, 0,
callback_data);
}
return;
}
......@@ -361,13 +404,12 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
t->tlabel = tlabel;
t->card = card;
t->is_split_transaction = false;
timer_setup(&t->split_timeout_timer,
split_transaction_timeout_callback, 0);
timer_setup(&t->split_timeout_timer, split_transaction_timeout_callback, 0);
t->callback = callback;
t->with_tstamp = with_tstamp;
t->callback_data = callback_data;
fw_fill_request(&t->packet, tcode, t->tlabel,
destination_id, card->node_id, generation,
fw_fill_request(&t->packet, tcode, t->tlabel, destination_id, card->node_id, generation,
speed, offset, payload, length);
t->packet.callback = transmit_complete_callback;
......@@ -377,7 +419,7 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
card->driver->send_request(card, &t->packet);
}
EXPORT_SYMBOL(fw_send_request);
EXPORT_SYMBOL_GPL(__fw_send_request);
struct transaction_callback_data {
struct completion done;
......@@ -1047,7 +1089,12 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
*/
card->driver->cancel_packet(card, &t->packet);
t->callback(card, rcode, data, data_length, t->callback_data);
if (!t->with_tstamp) {
t->callback.without_tstamp(card, rcode, data, data_length, t->callback_data);
} else {
t->callback.with_tstamp(card, rcode, t->packet.timestamp, p->timestamp, data,
data_length, t->callback_data);
}
}
EXPORT_SYMBOL(fw_core_handle_response);
......
......@@ -247,6 +247,13 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header,
void fw_request_get(struct fw_request *request);
void fw_request_put(struct fw_request *request);
// Convert the value of IEEE 1394 CYCLE_TIME register to the format of timeStamp field in
// descriptors of 1394 OHCI.
static inline u32 cycle_time_to_ohci_tstamp(u32 tstamp)
{
return (tstamp & 0x0ffff000) >> 12;
}
#define FW_PHY_CONFIG_NO_NODE_ID -1
#define FW_PHY_CONFIG_CURRENT_GAP_COUNT -1
void fw_send_phy_config(struct fw_card *card,
......
......@@ -479,7 +479,7 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
struct sk_buff *skb, u16 source_node_id,
bool is_broadcast, u16 ether_type)
{
int status;
int status, len;
switch (ether_type) {
case ETH_P_ARP:
......@@ -533,13 +533,15 @@ static int fwnet_finish_incoming_packet(struct net_device *net,
}
skb->protocol = protocol;
}
len = skb->len;
status = netif_rx(skb);
if (status == NET_RX_DROP) {
net->stats.rx_errors++;
net->stats.rx_dropped++;
} else {
net->stats.rx_packets++;
net->stats.rx_bytes += skb->len;
net->stats.rx_bytes += len;
}
return 0;
......
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0-only
//
// uapi_test.c - An application of Kunit to check layout of structures exposed to user space for
// FireWire subsystem.
//
// Copyright (c) 2023 Takashi Sakamoto
#include <kunit/test.h>
#include <linux/firewire-cdev.h>
// Known issue added at v2.6.27 kernel.
static void structure_layout_event_response(struct kunit *test)
{
#if defined(CONFIG_X86_32)
// 4 bytes alignment for aggregate type including 8 bytes storage types.
KUNIT_EXPECT_EQ(test, 20, sizeof(struct fw_cdev_event_response));
#else
// 8 bytes alignment for aggregate type including 8 bytes storage types.
KUNIT_EXPECT_EQ(test, 24, sizeof(struct fw_cdev_event_response));
#endif
KUNIT_EXPECT_EQ(test, 0, offsetof(struct fw_cdev_event_response, closure));
KUNIT_EXPECT_EQ(test, 8, offsetof(struct fw_cdev_event_response, type));
KUNIT_EXPECT_EQ(test, 12, offsetof(struct fw_cdev_event_response, rcode));
KUNIT_EXPECT_EQ(test, 16, offsetof(struct fw_cdev_event_response, length));
KUNIT_EXPECT_EQ(test, 20, offsetof(struct fw_cdev_event_response, data));
}
// Added at v6.5.
static void structure_layout_event_request3(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, 56, sizeof(struct fw_cdev_event_request3));
KUNIT_EXPECT_EQ(test, 0, offsetof(struct fw_cdev_event_request3, closure));
KUNIT_EXPECT_EQ(test, 8, offsetof(struct fw_cdev_event_request3, type));
KUNIT_EXPECT_EQ(test, 12, offsetof(struct fw_cdev_event_request3, tcode));
KUNIT_EXPECT_EQ(test, 16, offsetof(struct fw_cdev_event_request3, offset));
KUNIT_EXPECT_EQ(test, 24, offsetof(struct fw_cdev_event_request3, source_node_id));
KUNIT_EXPECT_EQ(test, 28, offsetof(struct fw_cdev_event_request3, destination_node_id));
KUNIT_EXPECT_EQ(test, 32, offsetof(struct fw_cdev_event_request3, card));
KUNIT_EXPECT_EQ(test, 36, offsetof(struct fw_cdev_event_request3, generation));
KUNIT_EXPECT_EQ(test, 40, offsetof(struct fw_cdev_event_request3, handle));
KUNIT_EXPECT_EQ(test, 44, offsetof(struct fw_cdev_event_request3, length));
KUNIT_EXPECT_EQ(test, 48, offsetof(struct fw_cdev_event_request3, tstamp));
KUNIT_EXPECT_EQ(test, 56, offsetof(struct fw_cdev_event_request3, data));
}
// Added at v6.5.
static void structure_layout_event_response2(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, 32, sizeof(struct fw_cdev_event_response2));
KUNIT_EXPECT_EQ(test, 0, offsetof(struct fw_cdev_event_response2, closure));
KUNIT_EXPECT_EQ(test, 8, offsetof(struct fw_cdev_event_response2, type));
KUNIT_EXPECT_EQ(test, 12, offsetof(struct fw_cdev_event_response2, rcode));
KUNIT_EXPECT_EQ(test, 16, offsetof(struct fw_cdev_event_response2, length));
KUNIT_EXPECT_EQ(test, 20, offsetof(struct fw_cdev_event_response2, request_tstamp));
KUNIT_EXPECT_EQ(test, 24, offsetof(struct fw_cdev_event_response2, response_tstamp));
KUNIT_EXPECT_EQ(test, 32, offsetof(struct fw_cdev_event_response2, data));
}
// Added at v6.5.
static void structure_layout_event_phy_packet2(struct kunit *test)
{
KUNIT_EXPECT_EQ(test, 24, sizeof(struct fw_cdev_event_phy_packet2));
KUNIT_EXPECT_EQ(test, 0, offsetof(struct fw_cdev_event_phy_packet2, closure));
KUNIT_EXPECT_EQ(test, 8, offsetof(struct fw_cdev_event_phy_packet2, type));
KUNIT_EXPECT_EQ(test, 12, offsetof(struct fw_cdev_event_phy_packet2, rcode));
KUNIT_EXPECT_EQ(test, 16, offsetof(struct fw_cdev_event_phy_packet2, length));
KUNIT_EXPECT_EQ(test, 20, offsetof(struct fw_cdev_event_phy_packet2, tstamp));
KUNIT_EXPECT_EQ(test, 24, offsetof(struct fw_cdev_event_phy_packet2, data));
}
static struct kunit_case structure_layout_test_cases[] = {
KUNIT_CASE(structure_layout_event_response),
KUNIT_CASE(structure_layout_event_request3),
KUNIT_CASE(structure_layout_event_response2),
KUNIT_CASE(structure_layout_event_phy_packet2),
{}
};
static struct kunit_suite structure_layout_test_suite = {
.name = "firewire-uapi-structure-layout",
.test_cases = structure_layout_test_cases,
};
kunit_test_suite(structure_layout_test_suite);
MODULE_LICENSE("GPL");
......@@ -261,6 +261,15 @@ typedef void (*fw_packet_callback_t)(struct fw_packet *packet,
typedef void (*fw_transaction_callback_t)(struct fw_card *card, int rcode,
void *data, size_t length,
void *callback_data);
typedef void (*fw_transaction_callback_with_tstamp_t)(struct fw_card *card, int rcode,
u32 request_tstamp, u32 response_tstamp, void *data,
size_t length, void *callback_data);
union fw_transaction_callback {
fw_transaction_callback_t without_tstamp;
fw_transaction_callback_with_tstamp_t with_tstamp;
};
/*
* This callback handles an inbound request subaction. It is called in
* RCU read-side context, therefore must not sleep.
......@@ -312,6 +321,7 @@ struct fw_transaction {
struct fw_card *card;
bool is_split_transaction;
struct timer_list split_timeout_timer;
u32 split_timeout_cycle;
struct fw_packet packet;
......@@ -319,7 +329,8 @@ struct fw_transaction {
* The data passed to the callback is valid only during the
* callback.
*/
fw_transaction_callback_t callback;
union fw_transaction_callback callback;
bool with_tstamp;
void *callback_data;
};
......@@ -345,10 +356,71 @@ void fw_send_response(struct fw_card *card,
struct fw_request *request, int rcode);
int fw_get_request_speed(struct fw_request *request);
u32 fw_request_get_timestamp(const struct fw_request *request);
void fw_send_request(struct fw_card *card, struct fw_transaction *t,
int tcode, int destination_id, int generation, int speed,
unsigned long long offset, void *payload, size_t length,
fw_transaction_callback_t callback, void *callback_data);
void __fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
int destination_id, int generation, int speed, unsigned long long offset,
void *payload, size_t length, union fw_transaction_callback callback,
bool with_tstamp, void *callback_data);
/**
* fw_send_request() - submit a request packet for transmission to generate callback for response
* subaction without time stamp.
* @card: interface to send the request at
* @t: transaction instance to which the request belongs
* @tcode: transaction code
* @destination_id: destination node ID, consisting of bus_ID and phy_ID
* @generation: bus generation in which request and response are valid
* @speed: transmission speed
* @offset: 48bit wide offset into destination's address space
* @payload: data payload for the request subaction
* @length: length of the payload, in bytes
* @callback: function to be called when the transaction is completed
* @callback_data: data to be passed to the transaction completion callback
*
* A variation of __fw_send_request() to generate callback for response subaction without time
* stamp.
*/
static inline void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
int destination_id, int generation, int speed,
unsigned long long offset, void *payload, size_t length,
fw_transaction_callback_t callback, void *callback_data)
{
union fw_transaction_callback cb = {
.without_tstamp = callback,
};
__fw_send_request(card, t, tcode, destination_id, generation, speed, offset, payload,
length, cb, false, callback_data);
}
/**
* fw_send_request_with_tstamp() - submit a request packet for transmission to generate callback for
* response with time stamp.
* @card: interface to send the request at
* @t: transaction instance to which the request belongs
* @tcode: transaction code
* @destination_id: destination node ID, consisting of bus_ID and phy_ID
* @generation: bus generation in which request and response are valid
* @speed: transmission speed
* @offset: 48bit wide offset into destination's address space
* @payload: data payload for the request subaction
* @length: length of the payload, in bytes
* @callback: function to be called when the transaction is completed
* @callback_data: data to be passed to the transaction completion callback
*
* A variation of __fw_send_request() to generate callback for response subaction with time stamp.
*/
static inline void fw_send_request_with_tstamp(struct fw_card *card, struct fw_transaction *t,
int tcode, int destination_id, int generation, int speed, unsigned long long offset,
void *payload, size_t length, fw_transaction_callback_with_tstamp_t callback,
void *callback_data)
{
union fw_transaction_callback cb = {
.with_tstamp = callback,
};
__fw_send_request(card, t, tcode, destination_id, generation, speed, offset, payload,
length, cb, true, callback_data);
}
int fw_cancel_transaction(struct fw_card *card,
struct fw_transaction *transaction);
int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment