diff options
Diffstat (limited to 'drivers/net/xen-netback/xenbus.c')
-rw-r--r-- | drivers/net/xen-netback/xenbus.c | 181 |
1 files changed, 180 insertions, 1 deletions
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 3d85acd84bad..9c47b897b6d2 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c | |||
@@ -44,6 +44,177 @@ static void unregister_hotplug_status_watch(struct backend_info *be); | |||
44 | static void set_backend_state(struct backend_info *be, | 44 | static void set_backend_state(struct backend_info *be, |
45 | enum xenbus_state state); | 45 | enum xenbus_state state); |
46 | 46 | ||
47 | #ifdef CONFIG_DEBUG_FS | ||
48 | struct dentry *xen_netback_dbg_root = NULL; | ||
49 | |||
50 | static int xenvif_read_io_ring(struct seq_file *m, void *v) | ||
51 | { | ||
52 | struct xenvif_queue *queue = m->private; | ||
53 | struct xen_netif_tx_back_ring *tx_ring = &queue->tx; | ||
54 | struct xen_netif_rx_back_ring *rx_ring = &queue->rx; | ||
55 | |||
56 | if (tx_ring->sring) { | ||
57 | struct xen_netif_tx_sring *sring = tx_ring->sring; | ||
58 | |||
59 | seq_printf(m, "Queue %d\nTX: nr_ents %u\n", queue->id, | ||
60 | tx_ring->nr_ents); | ||
61 | seq_printf(m, "req prod %u (%d) cons %u (%d) event %u (%d)\n", | ||
62 | sring->req_prod, | ||
63 | sring->req_prod - sring->rsp_prod, | ||
64 | tx_ring->req_cons, | ||
65 | tx_ring->req_cons - sring->rsp_prod, | ||
66 | sring->req_event, | ||
67 | sring->req_event - sring->rsp_prod); | ||
68 | seq_printf(m, "rsp prod %u (base) pvt %u (%d) event %u (%d)\n", | ||
69 | sring->rsp_prod, | ||
70 | tx_ring->rsp_prod_pvt, | ||
71 | tx_ring->rsp_prod_pvt - sring->rsp_prod, | ||
72 | sring->rsp_event, | ||
73 | sring->rsp_event - sring->rsp_prod); | ||
74 | seq_printf(m, "pending prod %u pending cons %u nr_pending_reqs %u\n", | ||
75 | queue->pending_prod, | ||
76 | queue->pending_cons, | ||
77 | nr_pending_reqs(queue)); | ||
78 | seq_printf(m, "dealloc prod %u dealloc cons %u dealloc_queue %u\n\n", | ||
79 | queue->dealloc_prod, | ||
80 | queue->dealloc_cons, | ||
81 | queue->dealloc_prod - queue->dealloc_cons); | ||
82 | } | ||
83 | |||
84 | if (rx_ring->sring) { | ||
85 | struct xen_netif_rx_sring *sring = rx_ring->sring; | ||
86 | |||
87 | seq_printf(m, "RX: nr_ents %u\n", rx_ring->nr_ents); | ||
88 | seq_printf(m, "req prod %u (%d) cons %u (%d) event %u (%d)\n", | ||
89 | sring->req_prod, | ||
90 | sring->req_prod - sring->rsp_prod, | ||
91 | rx_ring->req_cons, | ||
92 | rx_ring->req_cons - sring->rsp_prod, | ||
93 | sring->req_event, | ||
94 | sring->req_event - sring->rsp_prod); | ||
95 | seq_printf(m, "rsp prod %u (base) pvt %u (%d) event %u (%d)\n\n", | ||
96 | sring->rsp_prod, | ||
97 | rx_ring->rsp_prod_pvt, | ||
98 | rx_ring->rsp_prod_pvt - sring->rsp_prod, | ||
99 | sring->rsp_event, | ||
100 | sring->rsp_event - sring->rsp_prod); | ||
101 | } | ||
102 | |||
103 | seq_printf(m, "NAPI state: %lx NAPI weight: %d TX queue len %u\n" | ||
104 | "Credit timer_pending: %d, credit: %lu, usec: %lu\n" | ||
105 | "remaining: %lu, expires: %lu, now: %lu\n", | ||
106 | queue->napi.state, queue->napi.weight, | ||
107 | skb_queue_len(&queue->tx_queue), | ||
108 | timer_pending(&queue->credit_timeout), | ||
109 | queue->credit_bytes, | ||
110 | queue->credit_usec, | ||
111 | queue->remaining_credit, | ||
112 | queue->credit_timeout.expires, | ||
113 | jiffies); | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | #define XENVIF_KICK_STR "kick" | ||
119 | #define BUFFER_SIZE 32 | ||
120 | |||
121 | static ssize_t | ||
122 | xenvif_write_io_ring(struct file *filp, const char __user *buf, size_t count, | ||
123 | loff_t *ppos) | ||
124 | { | ||
125 | struct xenvif_queue *queue = | ||
126 | ((struct seq_file *)filp->private_data)->private; | ||
127 | int len; | ||
128 | char write[BUFFER_SIZE]; | ||
129 | |||
130 | /* don't allow partial writes and check the length */ | ||
131 | if (*ppos != 0) | ||
132 | return 0; | ||
133 | if (count >= sizeof(write)) | ||
134 | return -ENOSPC; | ||
135 | |||
136 | len = simple_write_to_buffer(write, | ||
137 | sizeof(write) - 1, | ||
138 | ppos, | ||
139 | buf, | ||
140 | count); | ||
141 | if (len < 0) | ||
142 | return len; | ||
143 | |||
144 | write[len] = '\0'; | ||
145 | |||
146 | if (!strncmp(write, XENVIF_KICK_STR, sizeof(XENVIF_KICK_STR) - 1)) | ||
147 | xenvif_interrupt(0, (void *)queue); | ||
148 | else { | ||
149 | pr_warn("Unknown command to io_ring_q%d. Available: kick\n", | ||
150 | queue->id); | ||
151 | count = -EINVAL; | ||
152 | } | ||
153 | return count; | ||
154 | } | ||
155 | |||
156 | static int xenvif_dump_open(struct inode *inode, struct file *filp) | ||
157 | { | ||
158 | int ret; | ||
159 | void *queue = NULL; | ||
160 | |||
161 | if (inode->i_private) | ||
162 | queue = inode->i_private; | ||
163 | ret = single_open(filp, xenvif_read_io_ring, queue); | ||
164 | filp->f_mode |= FMODE_PWRITE; | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | static const struct file_operations xenvif_dbg_io_ring_ops_fops = { | ||
169 | .owner = THIS_MODULE, | ||
170 | .open = xenvif_dump_open, | ||
171 | .read = seq_read, | ||
172 | .llseek = seq_lseek, | ||
173 | .release = single_release, | ||
174 | .write = xenvif_write_io_ring, | ||
175 | }; | ||
176 | |||
177 | static void xenvif_debugfs_addif(struct xenvif *vif) | ||
178 | { | ||
179 | struct dentry *pfile; | ||
180 | int i; | ||
181 | |||
182 | if (IS_ERR_OR_NULL(xen_netback_dbg_root)) | ||
183 | return; | ||
184 | |||
185 | vif->xenvif_dbg_root = debugfs_create_dir(vif->dev->name, | ||
186 | xen_netback_dbg_root); | ||
187 | if (!IS_ERR_OR_NULL(vif->xenvif_dbg_root)) { | ||
188 | for (i = 0; i < vif->num_queues; ++i) { | ||
189 | char filename[sizeof("io_ring_q") + 4]; | ||
190 | |||
191 | snprintf(filename, sizeof(filename), "io_ring_q%d", i); | ||
192 | pfile = debugfs_create_file(filename, | ||
193 | S_IRUSR | S_IWUSR, | ||
194 | vif->xenvif_dbg_root, | ||
195 | &vif->queues[i], | ||
196 | &xenvif_dbg_io_ring_ops_fops); | ||
197 | if (IS_ERR_OR_NULL(pfile)) | ||
198 | pr_warn("Creation of io_ring file returned %ld!\n", | ||
199 | PTR_ERR(pfile)); | ||
200 | } | ||
201 | } else | ||
202 | netdev_warn(vif->dev, | ||
203 | "Creation of vif debugfs dir returned %ld!\n", | ||
204 | PTR_ERR(vif->xenvif_dbg_root)); | ||
205 | } | ||
206 | |||
207 | static void xenvif_debugfs_delif(struct xenvif *vif) | ||
208 | { | ||
209 | if (IS_ERR_OR_NULL(xen_netback_dbg_root)) | ||
210 | return; | ||
211 | |||
212 | if (!IS_ERR_OR_NULL(vif->xenvif_dbg_root)) | ||
213 | debugfs_remove_recursive(vif->xenvif_dbg_root); | ||
214 | vif->xenvif_dbg_root = NULL; | ||
215 | } | ||
216 | #endif /* CONFIG_DEBUG_FS */ | ||
217 | |||
47 | static int netback_remove(struct xenbus_device *dev) | 218 | static int netback_remove(struct xenbus_device *dev) |
48 | { | 219 | { |
49 | struct backend_info *be = dev_get_drvdata(&dev->dev); | 220 | struct backend_info *be = dev_get_drvdata(&dev->dev); |
@@ -246,8 +417,12 @@ static void backend_create_xenvif(struct backend_info *be) | |||
246 | 417 | ||
247 | static void backend_disconnect(struct backend_info *be) | 418 | static void backend_disconnect(struct backend_info *be) |
248 | { | 419 | { |
249 | if (be->vif) | 420 | if (be->vif) { |
421 | #ifdef CONFIG_DEBUG_FS | ||
422 | xenvif_debugfs_delif(be->vif); | ||
423 | #endif /* CONFIG_DEBUG_FS */ | ||
250 | xenvif_disconnect(be->vif); | 424 | xenvif_disconnect(be->vif); |
425 | } | ||
251 | } | 426 | } |
252 | 427 | ||
253 | static void backend_connect(struct backend_info *be) | 428 | static void backend_connect(struct backend_info *be) |
@@ -562,6 +737,10 @@ static void connect(struct backend_info *be) | |||
562 | } | 737 | } |
563 | } | 738 | } |
564 | 739 | ||
740 | #ifdef CONFIG_DEBUG_FS | ||
741 | xenvif_debugfs_addif(be->vif); | ||
742 | #endif /* CONFIG_DEBUG_FS */ | ||
743 | |||
565 | /* Initialisation completed, tell core driver the number of | 744 | /* Initialisation completed, tell core driver the number of |
566 | * active queues. | 745 | * active queues. |
567 | */ | 746 | */ |