mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-24 07:31:41 +00:00
vmbus: add direct isr callback mode
Change the simple boolean batched_reading into a tri-value. For future NAPI support in netvsc driver, the callback needs to occur directly in interrupt handler. Batched mode is also changed to disable host interrupts immediately in interrupt routine (to avoid unnecessary host signals), and the tasklet is rescheduled if more data is detected. Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
631e63a9f3
commit
b71e328297
6 changed files with 55 additions and 41 deletions
|
@ -819,13 +819,6 @@ static void vmbus_onoffer(struct vmbus_channel_message_header *hdr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* By default we setup state to enable batched
|
|
||||||
* reading. A specific service can choose to
|
|
||||||
* disable this prior to opening the channel.
|
|
||||||
*/
|
|
||||||
newchannel->batched_reading = true;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup state for signalling the host.
|
* Setup state for signalling the host.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -300,9 +300,7 @@ struct vmbus_channel *relid2channel(u32 relid)
|
||||||
void vmbus_on_event(unsigned long data)
|
void vmbus_on_event(unsigned long data)
|
||||||
{
|
{
|
||||||
struct vmbus_channel *channel = (void *) data;
|
struct vmbus_channel *channel = (void *) data;
|
||||||
void *arg;
|
void (*callback_fn)(void *);
|
||||||
bool read_state;
|
|
||||||
u32 bytes_to_read;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A channel once created is persistent even when there
|
* A channel once created is persistent even when there
|
||||||
|
@ -312,9 +310,13 @@ void vmbus_on_event(unsigned long data)
|
||||||
* Thus, checking and invoking the driver specific callback takes
|
* Thus, checking and invoking the driver specific callback takes
|
||||||
* care of orderly unloading of the driver.
|
* care of orderly unloading of the driver.
|
||||||
*/
|
*/
|
||||||
if (channel->onchannel_callback != NULL) {
|
callback_fn = READ_ONCE(channel->onchannel_callback);
|
||||||
arg = channel->channel_callback_context;
|
if (unlikely(callback_fn == NULL))
|
||||||
read_state = channel->batched_reading;
|
return;
|
||||||
|
|
||||||
|
(*callback_fn)(channel->channel_callback_context);
|
||||||
|
|
||||||
|
if (channel->callback_mode == HV_CALL_BATCHED) {
|
||||||
/*
|
/*
|
||||||
* This callback reads the messages sent by the host.
|
* This callback reads the messages sent by the host.
|
||||||
* We can optimize host to guest signaling by ensuring:
|
* We can optimize host to guest signaling by ensuring:
|
||||||
|
@ -326,16 +328,11 @@ void vmbus_on_event(unsigned long data)
|
||||||
* state is set we check to see if additional packets are
|
* state is set we check to see if additional packets are
|
||||||
* available to read. In this case we repeat the process.
|
* available to read. In this case we repeat the process.
|
||||||
*/
|
*/
|
||||||
|
if (hv_end_read(&channel->inbound) != 0) {
|
||||||
|
hv_begin_read(&channel->inbound);
|
||||||
|
|
||||||
do {
|
tasklet_schedule(&channel->callback_event);
|
||||||
if (read_state)
|
}
|
||||||
hv_begin_read(&channel->inbound);
|
|
||||||
channel->onchannel_callback(arg);
|
|
||||||
if (read_state)
|
|
||||||
bytes_to_read = hv_end_read(&channel->inbound);
|
|
||||||
else
|
|
||||||
bytes_to_read = 0;
|
|
||||||
} while (read_state && (bytes_to_read != 0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -435,8 +435,7 @@ static int util_probe(struct hv_device *dev,
|
||||||
* Turn off batched reading for all util drivers before we open the
|
* Turn off batched reading for all util drivers before we open the
|
||||||
* channel.
|
* channel.
|
||||||
*/
|
*/
|
||||||
|
set_channel_read_mode(dev->channel, HV_CALL_DIRECT);
|
||||||
set_channel_read_state(dev->channel, false);
|
|
||||||
|
|
||||||
hv_set_drvdata(dev, srv);
|
hv_set_drvdata(dev, srv);
|
||||||
|
|
||||||
|
|
|
@ -886,6 +886,18 @@ msg_handled:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Direct callback for channels using other deferred processing
|
||||||
|
*/
|
||||||
|
static void vmbus_channel_isr(struct vmbus_channel *channel)
|
||||||
|
{
|
||||||
|
void (*callback_fn)(void *);
|
||||||
|
|
||||||
|
callback_fn = READ_ONCE(channel->onchannel_callback);
|
||||||
|
if (likely(callback_fn != NULL))
|
||||||
|
(*callback_fn)(channel->channel_callback_context);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Schedule all channels with events pending
|
* Schedule all channels with events pending
|
||||||
*/
|
*/
|
||||||
|
@ -927,9 +939,19 @@ static void vmbus_chan_sched(struct hv_per_cpu_context *hv_cpu)
|
||||||
|
|
||||||
/* Find channel based on relid */
|
/* Find channel based on relid */
|
||||||
list_for_each_entry(channel, &hv_cpu->chan_list, percpu_list) {
|
list_for_each_entry(channel, &hv_cpu->chan_list, percpu_list) {
|
||||||
if (channel->offermsg.child_relid == relid) {
|
if (channel->offermsg.child_relid != relid)
|
||||||
tasklet_schedule(&channel->callback_event);
|
continue;
|
||||||
|
|
||||||
|
switch (channel->callback_mode) {
|
||||||
|
case HV_CALL_ISR:
|
||||||
|
vmbus_channel_isr(channel);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case HV_CALL_BATCHED:
|
||||||
|
hv_begin_read(&channel->inbound);
|
||||||
|
/* fallthrough */
|
||||||
|
case HV_CALL_DIRECT:
|
||||||
|
tasklet_schedule(&channel->callback_event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,7 @@ hv_uio_probe(struct hv_device *dev,
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
dev->channel->inbound.ring_buffer->interrupt_mask = 1;
|
dev->channel->inbound.ring_buffer->interrupt_mask = 1;
|
||||||
dev->channel->batched_reading = false;
|
set_channel_read_mode(dev->channel, HV_CALL_DIRECT);
|
||||||
|
|
||||||
/* Fill general uio info */
|
/* Fill general uio info */
|
||||||
pdata->info.name = "uio_hv_generic";
|
pdata->info.name = "uio_hv_generic";
|
||||||
|
|
|
@ -748,19 +748,21 @@ struct vmbus_channel {
|
||||||
void *channel_callback_context;
|
void *channel_callback_context;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A channel can be marked for efficient (batched)
|
* A channel can be marked for one of three modes of reading:
|
||||||
* reading:
|
* BATCHED - callback called from taslket and should read
|
||||||
* If batched_reading is set to "true", we read until the
|
* channel until empty. Interrupts from the host
|
||||||
* channel is empty and hold off interrupts from the host
|
* are masked while read is in process (default).
|
||||||
* during the entire read process.
|
* DIRECT - callback called from tasklet (softirq).
|
||||||
* If batched_reading is set to "false", the client is not
|
* ISR - callback called in interrupt context and must
|
||||||
* going to perform batched reading.
|
* invoke its own deferred processing.
|
||||||
*
|
* Host interrupts are disabled and must be re-enabled
|
||||||
* By default we will enable batched reading; specific
|
* when ring is empty.
|
||||||
* drivers that don't want this behavior can turn it off.
|
|
||||||
*/
|
*/
|
||||||
|
enum hv_callback_mode {
|
||||||
bool batched_reading;
|
HV_CALL_BATCHED,
|
||||||
|
HV_CALL_DIRECT,
|
||||||
|
HV_CALL_ISR
|
||||||
|
} callback_mode;
|
||||||
|
|
||||||
bool is_dedicated_interrupt;
|
bool is_dedicated_interrupt;
|
||||||
struct hv_input_signal_event_buffer sig_buf;
|
struct hv_input_signal_event_buffer sig_buf;
|
||||||
|
@ -910,9 +912,10 @@ static inline void set_channel_affinity_state(struct vmbus_channel *c,
|
||||||
c->affinity_policy = policy;
|
c->affinity_policy = policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void set_channel_read_state(struct vmbus_channel *c, bool state)
|
static inline void set_channel_read_mode(struct vmbus_channel *c,
|
||||||
|
enum hv_callback_mode mode)
|
||||||
{
|
{
|
||||||
c->batched_reading = state;
|
c->callback_mode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void set_per_channel_state(struct vmbus_channel *c, void *s)
|
static inline void set_per_channel_state(struct vmbus_channel *c, void *s)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue