Revision f2efc6e60089c99c342a6b7da47f1037e06c4296 authored by Shirish S on 30 October 2019, 08:50:46 UTC, committed by Alex Deucher on 06 November 2019, 20:26:53 UTC
[Why]

doing kthread_park()/unpark() from drm_sched_entity_fini
while GPU reset is in progress defeats all the purpose of
drm_sched_stop->kthread_park.
If drm_sched_entity_fini->kthread_unpark() happens AFTER
drm_sched_stop->kthread_park nothing prevents from another
(third) thread to keep submitting job to HW which will be
picked up by the unparked scheduler thread and try to submit
to HW but fail because the HW ring is deactivated.

[How]
grab the reset lock before calling drm_sched_entity_fini()

Signed-off-by: Shirish S <shirish.s@amd.com>
Suggested-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Andrey Grodzovsky <andrey.grodzovsky@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
1 parent 576daab
Raw File
midi.c
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 *   Copyright (c) 2006,2007 Daniel Mack
*/

#include <linux/device.h>
#include <linux/usb.h>
#include <linux/gfp.h>
#include <sound/rawmidi.h>
#include <sound/core.h>
#include <sound/pcm.h>

#include "device.h"
#include "midi.h"

static int snd_usb_caiaq_midi_input_open(struct snd_rawmidi_substream *substream)
{
	return 0;
}

static int snd_usb_caiaq_midi_input_close(struct snd_rawmidi_substream *substream)
{
	return 0;
}

static void snd_usb_caiaq_midi_input_trigger(struct snd_rawmidi_substream *substream, int up)
{
	struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;

	if (!cdev)
		return;

	cdev->midi_receive_substream = up ? substream : NULL;
}


static int snd_usb_caiaq_midi_output_open(struct snd_rawmidi_substream *substream)
{
	return 0;
}

static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substream)
{
	struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;
	if (cdev->midi_out_active) {
		usb_kill_urb(&cdev->midi_out_urb);
		cdev->midi_out_active = 0;
	}
	return 0;
}

static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *cdev,
				    struct snd_rawmidi_substream *substream)
{
	int len, ret;
	struct device *dev = caiaqdev_to_dev(cdev);

	cdev->midi_out_buf[0] = EP1_CMD_MIDI_WRITE;
	cdev->midi_out_buf[1] = 0; /* port */
	len = snd_rawmidi_transmit(substream, cdev->midi_out_buf + 3,
				   EP1_BUFSIZE - 3);

	if (len <= 0)
		return;

	cdev->midi_out_buf[2] = len;
	cdev->midi_out_urb.transfer_buffer_length = len+3;

	ret = usb_submit_urb(&cdev->midi_out_urb, GFP_ATOMIC);
	if (ret < 0)
		dev_err(dev,
			"snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
			"ret=%d, len=%d\n", substream, ret, len);
	else
		cdev->midi_out_active = 1;
}

static void snd_usb_caiaq_midi_output_trigger(struct snd_rawmidi_substream *substream, int up)
{
	struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;

	if (up) {
		cdev->midi_out_substream = substream;
		if (!cdev->midi_out_active)
			snd_usb_caiaq_midi_send(cdev, substream);
	} else {
		cdev->midi_out_substream = NULL;
	}
}


static const struct snd_rawmidi_ops snd_usb_caiaq_midi_output =
{
	.open =		snd_usb_caiaq_midi_output_open,
	.close =	snd_usb_caiaq_midi_output_close,
	.trigger =      snd_usb_caiaq_midi_output_trigger,
};

static const struct snd_rawmidi_ops snd_usb_caiaq_midi_input =
{
	.open =		snd_usb_caiaq_midi_input_open,
	.close =	snd_usb_caiaq_midi_input_close,
	.trigger =      snd_usb_caiaq_midi_input_trigger,
};

void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *cdev,
				     int port, const char *buf, int len)
{
	if (!cdev->midi_receive_substream)
		return;

	snd_rawmidi_receive(cdev->midi_receive_substream, buf, len);
}

int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *device)
{
	int ret;
	struct snd_rawmidi *rmidi;

	ret = snd_rawmidi_new(device->chip.card, device->product_name, 0,
					device->spec.num_midi_out,
					device->spec.num_midi_in,
					&rmidi);

	if (ret < 0)
		return ret;

	strlcpy(rmidi->name, device->product_name, sizeof(rmidi->name));

	rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
	rmidi->private_data = device;

	if (device->spec.num_midi_out > 0) {
		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
				    &snd_usb_caiaq_midi_output);
	}

	if (device->spec.num_midi_in > 0) {
		rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
		snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
				    &snd_usb_caiaq_midi_input);
	}

	device->rmidi = rmidi;

	return 0;
}

void snd_usb_caiaq_midi_output_done(struct urb* urb)
{
	struct snd_usb_caiaqdev *cdev = urb->context;

	cdev->midi_out_active = 0;
	if (urb->status != 0)
		return;

	if (!cdev->midi_out_substream)
		return;

	snd_usb_caiaq_midi_send(cdev, cdev->midi_out_substream);
}
back to top