aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTaku Izumi <izumi.taku@jp.fujitsu.com>2015-08-21 04:29:23 -0400
committerDavid S. Miller <davem@davemloft.net>2015-08-24 17:06:34 -0400
commite5d486dcaa45dd365970c09395ae24df5a0e3f77 (patch)
tree237e68516fdbf7e3276c2524508397f9b0dbc31a
parent7950e6c5da55715debef9fa06b5ac87fb3eb4355 (diff)
fjes: net_device_ops.ndo_open and .ndo_stop
This patch adds net_device_ops.ndo_open and .ndo_stop callback. These function is called when network device activation and deactivation. Signed-off-by: Taku Izumi <izumi.taku@jp.fujitsu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/fjes/fjes.h1
-rw-r--r--drivers/net/fjes/fjes_hw.c145
-rw-r--r--drivers/net/fjes/fjes_hw.h30
-rw-r--r--drivers/net/fjes/fjes_main.c246
-rw-r--r--drivers/net/fjes/fjes_regs.h17
5 files changed, 439 insertions, 0 deletions
diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h
index 54bc189a997c..f182ed3a4cd1 100644
--- a/drivers/net/fjes/fjes.h
+++ b/drivers/net/fjes/fjes.h
@@ -29,6 +29,7 @@
29#define FJES_ACPI_SYMBOL "Extended Socket" 29#define FJES_ACPI_SYMBOL "Extended Socket"
30#define FJES_MAX_QUEUES 1 30#define FJES_MAX_QUEUES 1
31#define FJES_TX_RETRY_INTERVAL (20 * HZ) 31#define FJES_TX_RETRY_INTERVAL (20 * HZ)
32#define FJES_OPEN_ZONE_UPDATE_WAIT (300) /* msec */
32 33
33/* board specific private data structure */ 34/* board specific private data structure */
34struct fjes_adapter { 35struct fjes_adapter {
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 1e807dfc548a..1935f48e9e43 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c
@@ -638,6 +638,25 @@ int fjes_hw_unregister_buff_addr(struct fjes_hw *hw, int dest_epid)
638 return result; 638 return result;
639} 639}
640 640
641int fjes_hw_raise_interrupt(struct fjes_hw *hw, int dest_epid,
642 enum REG_ICTL_MASK mask)
643{
644 u32 ig = mask | dest_epid;
645
646 wr32(XSCT_IG, cpu_to_le32(ig));
647
648 return 0;
649}
650
651u32 fjes_hw_capture_interrupt_status(struct fjes_hw *hw)
652{
653 u32 cur_is;
654
655 cur_is = rd32(XSCT_IS);
656
657 return cur_is;
658}
659
641void fjes_hw_set_irqmask(struct fjes_hw *hw, 660void fjes_hw_set_irqmask(struct fjes_hw *hw,
642 enum REG_ICTL_MASK intr_mask, bool mask) 661 enum REG_ICTL_MASK intr_mask, bool mask)
643{ 662{
@@ -646,3 +665,129 @@ void fjes_hw_set_irqmask(struct fjes_hw *hw,
646 else 665 else
647 wr32(XSCT_IMC, intr_mask); 666 wr32(XSCT_IMC, intr_mask);
648} 667}
668
669bool fjes_hw_epid_is_same_zone(struct fjes_hw *hw, int epid)
670{
671 if (epid >= hw->max_epid)
672 return false;
673
674 if ((hw->ep_shm_info[epid].es_status !=
675 FJES_ZONING_STATUS_ENABLE) ||
676 (hw->ep_shm_info[hw->my_epid].zone ==
677 FJES_ZONING_ZONE_TYPE_NONE))
678 return false;
679 else
680 return (hw->ep_shm_info[epid].zone ==
681 hw->ep_shm_info[hw->my_epid].zone);
682}
683
684int fjes_hw_epid_is_shared(struct fjes_device_shared_info *share,
685 int dest_epid)
686{
687 int value = false;
688
689 if (dest_epid < share->epnum)
690 value = share->ep_status[dest_epid];
691
692 return value;
693}
694
695static bool fjes_hw_epid_is_stop_requested(struct fjes_hw *hw, int src_epid)
696{
697 return test_bit(src_epid, &hw->txrx_stop_req_bit);
698}
699
700static bool fjes_hw_epid_is_stop_process_done(struct fjes_hw *hw, int src_epid)
701{
702 return (hw->ep_shm_info[src_epid].tx.info->v1i.rx_status &
703 FJES_RX_STOP_REQ_DONE);
704}
705
706enum ep_partner_status
707fjes_hw_get_partner_ep_status(struct fjes_hw *hw, int epid)
708{
709 enum ep_partner_status status;
710
711 if (fjes_hw_epid_is_shared(hw->hw_info.share, epid)) {
712 if (fjes_hw_epid_is_stop_requested(hw, epid)) {
713 status = EP_PARTNER_WAITING;
714 } else {
715 if (fjes_hw_epid_is_stop_process_done(hw, epid))
716 status = EP_PARTNER_COMPLETE;
717 else
718 status = EP_PARTNER_SHARED;
719 }
720 } else {
721 status = EP_PARTNER_UNSHARE;
722 }
723
724 return status;
725}
726
727void fjes_hw_raise_epstop(struct fjes_hw *hw)
728{
729 enum ep_partner_status status;
730 int epidx;
731
732 for (epidx = 0; epidx < hw->max_epid; epidx++) {
733 if (epidx == hw->my_epid)
734 continue;
735
736 status = fjes_hw_get_partner_ep_status(hw, epidx);
737 switch (status) {
738 case EP_PARTNER_SHARED:
739 fjes_hw_raise_interrupt(hw, epidx,
740 REG_ICTL_MASK_TXRX_STOP_REQ);
741 break;
742 default:
743 break;
744 }
745
746 set_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit);
747 set_bit(epidx, &hw->txrx_stop_req_bit);
748
749 hw->ep_shm_info[epidx].tx.info->v1i.rx_status |=
750 FJES_RX_STOP_REQ_REQUEST;
751 }
752}
753
754int fjes_hw_wait_epstop(struct fjes_hw *hw)
755{
756 enum ep_partner_status status;
757 union ep_buffer_info *info;
758 int wait_time = 0;
759 int epidx;
760
761 while (hw->hw_info.buffer_unshare_reserve_bit &&
762 (wait_time < FJES_COMMAND_EPSTOP_WAIT_TIMEOUT * 1000)) {
763 for (epidx = 0; epidx < hw->max_epid; epidx++) {
764 if (epidx == hw->my_epid)
765 continue;
766 status = fjes_hw_epid_is_shared(hw->hw_info.share,
767 epidx);
768 info = hw->ep_shm_info[epidx].rx.info;
769 if ((!status ||
770 (info->v1i.rx_status &
771 FJES_RX_STOP_REQ_DONE)) &&
772 test_bit(epidx,
773 &hw->hw_info.buffer_unshare_reserve_bit)) {
774 clear_bit(epidx,
775 &hw->hw_info.buffer_unshare_reserve_bit);
776 }
777 }
778
779 msleep(100);
780 wait_time += 100;
781 }
782
783 for (epidx = 0; epidx < hw->max_epid; epidx++) {
784 if (epidx == hw->my_epid)
785 continue;
786 if (test_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit))
787 clear_bit(epidx,
788 &hw->hw_info.buffer_unshare_reserve_bit);
789 }
790
791 return (wait_time < FJES_COMMAND_EPSTOP_WAIT_TIMEOUT * 1000)
792 ? 0 : -EBUSY;
793}
diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h
index 2e750e9655ef..9b8df553f730 100644
--- a/drivers/net/fjes/fjes_hw.h
+++ b/drivers/net/fjes/fjes_hw.h
@@ -36,6 +36,7 @@ struct fjes_hw;
36#define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */ 36#define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */
37#define FJES_COMMAND_REQ_TIMEOUT (5 + 1) /* sec */ 37#define FJES_COMMAND_REQ_TIMEOUT (5 + 1) /* sec */
38#define FJES_COMMAND_REQ_BUFF_TIMEOUT (8 * 3) /* sec */ 38#define FJES_COMMAND_REQ_BUFF_TIMEOUT (8 * 3) /* sec */
39#define FJES_COMMAND_EPSTOP_WAIT_TIMEOUT (1) /* sec */
39 40
40#define FJES_CMD_REQ_ERR_INFO_PARAM (0x0001) 41#define FJES_CMD_REQ_ERR_INFO_PARAM (0x0001)
41#define FJES_CMD_REQ_ERR_INFO_STATUS (0x0002) 42#define FJES_CMD_REQ_ERR_INFO_STATUS (0x0002)
@@ -43,6 +44,17 @@ struct fjes_hw;
43#define FJES_CMD_REQ_RES_CODE_NORMAL (0) 44#define FJES_CMD_REQ_RES_CODE_NORMAL (0)
44#define FJES_CMD_REQ_RES_CODE_BUSY (1) 45#define FJES_CMD_REQ_RES_CODE_BUSY (1)
45 46
47#define FJES_ZONING_STATUS_DISABLE (0x00)
48#define FJES_ZONING_STATUS_ENABLE (0x01)
49#define FJES_ZONING_STATUS_INVALID (0xFF)
50
51#define FJES_ZONING_ZONE_TYPE_NONE (0xFF)
52
53#define FJES_RX_STOP_REQ_NONE (0x0)
54#define FJES_RX_STOP_REQ_DONE (0x1)
55#define FJES_RX_STOP_REQ_REQUEST (0x2)
56#define FJES_RX_POLL_WORK (0x4)
57
46#define EP_BUFFER_SIZE \ 58#define EP_BUFFER_SIZE \
47 (((sizeof(union ep_buffer_info) + (128 * (64 * 1024))) \ 59 (((sizeof(union ep_buffer_info) + (128 * (64 * 1024))) \
48 / EP_BUFFER_INFO_SIZE) * EP_BUFFER_INFO_SIZE) 60 / EP_BUFFER_INFO_SIZE) * EP_BUFFER_INFO_SIZE)
@@ -77,6 +89,15 @@ struct esmem_frame {
77 u8 frame_data[]; 89 u8 frame_data[];
78}; 90};
79 91
92/* EP partner status */
93enum ep_partner_status {
94 EP_PARTNER_UNSHARE,
95 EP_PARTNER_SHARED,
96 EP_PARTNER_WAITING,
97 EP_PARTNER_COMPLETE,
98 EP_PARTNER_STATUS_MAX,
99};
100
80/* shared status region */ 101/* shared status region */
81struct fjes_device_shared_info { 102struct fjes_device_shared_info {
82 int epnum; 103 int epnum;
@@ -278,6 +299,15 @@ int fjes_hw_unregister_buff_addr(struct fjes_hw *, int);
278void fjes_hw_init_command_registers(struct fjes_hw *, 299void fjes_hw_init_command_registers(struct fjes_hw *,
279 struct fjes_device_command_param *); 300 struct fjes_device_command_param *);
280void fjes_hw_setup_epbuf(struct epbuf_handler *, u8 *, u32); 301void fjes_hw_setup_epbuf(struct epbuf_handler *, u8 *, u32);
302int fjes_hw_raise_interrupt(struct fjes_hw *, int, enum REG_ICTL_MASK);
281void fjes_hw_set_irqmask(struct fjes_hw *, enum REG_ICTL_MASK, bool); 303void fjes_hw_set_irqmask(struct fjes_hw *, enum REG_ICTL_MASK, bool);
304u32 fjes_hw_capture_interrupt_status(struct fjes_hw *);
305void fjes_hw_raise_epstop(struct fjes_hw *);
306int fjes_hw_wait_epstop(struct fjes_hw *);
307enum ep_partner_status
308 fjes_hw_get_partner_ep_status(struct fjes_hw *, int);
309
310bool fjes_hw_epid_is_same_zone(struct fjes_hw *, int);
311int fjes_hw_epid_is_shared(struct fjes_device_shared_info *, int);
282 312
283#endif /* FJES_HW_H_ */ 313#endif /* FJES_HW_H_ */
diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c
index 45a8b9c52ae5..bd50cbd6915f 100644
--- a/drivers/net/fjes/fjes_main.c
+++ b/drivers/net/fjes/fjes_main.c
@@ -24,6 +24,7 @@
24#include <linux/nls.h> 24#include <linux/nls.h>
25#include <linux/platform_device.h> 25#include <linux/platform_device.h>
26#include <linux/netdevice.h> 26#include <linux/netdevice.h>
27#include <linux/interrupt.h>
27 28
28#include "fjes.h" 29#include "fjes.h"
29 30
@@ -43,6 +44,15 @@ MODULE_DESCRIPTION("FUJITSU Extended Socket Network Device Driver");
43MODULE_LICENSE("GPL"); 44MODULE_LICENSE("GPL");
44MODULE_VERSION(DRV_VERSION); 45MODULE_VERSION(DRV_VERSION);
45 46
47static int fjes_request_irq(struct fjes_adapter *);
48static void fjes_free_irq(struct fjes_adapter *);
49
50static int fjes_open(struct net_device *);
51static int fjes_close(struct net_device *);
52static int fjes_setup_resources(struct fjes_adapter *);
53static void fjes_free_resources(struct fjes_adapter *);
54static irqreturn_t fjes_intr(int, void*);
55
46static int fjes_acpi_add(struct acpi_device *); 56static int fjes_acpi_add(struct acpi_device *);
47static int fjes_acpi_remove(struct acpi_device *); 57static int fjes_acpi_remove(struct acpi_device *);
48static acpi_status fjes_get_acpi_resource(struct acpi_resource *, void*); 58static acpi_status fjes_get_acpi_resource(struct acpi_resource *, void*);
@@ -170,9 +180,245 @@ fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data)
170 return AE_OK; 180 return AE_OK;
171} 181}
172 182
183static int fjes_request_irq(struct fjes_adapter *adapter)
184{
185 struct net_device *netdev = adapter->netdev;
186 int result = -1;
187
188 if (!adapter->irq_registered) {
189 result = request_irq(adapter->hw.hw_res.irq, fjes_intr,
190 IRQF_SHARED, netdev->name, adapter);
191 if (result)
192 adapter->irq_registered = false;
193 else
194 adapter->irq_registered = true;
195 }
196
197 return result;
198}
199
200static void fjes_free_irq(struct fjes_adapter *adapter)
201{
202 struct fjes_hw *hw = &adapter->hw;
203
204 fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true);
205
206 if (adapter->irq_registered) {
207 free_irq(adapter->hw.hw_res.irq, adapter);
208 adapter->irq_registered = false;
209 }
210}
211
173static const struct net_device_ops fjes_netdev_ops = { 212static const struct net_device_ops fjes_netdev_ops = {
213 .ndo_open = fjes_open,
214 .ndo_stop = fjes_close,
174}; 215};
175 216
217/* fjes_open - Called when a network interface is made active */
218static int fjes_open(struct net_device *netdev)
219{
220 struct fjes_adapter *adapter = netdev_priv(netdev);
221 struct fjes_hw *hw = &adapter->hw;
222 int result;
223
224 if (adapter->open_guard)
225 return -ENXIO;
226
227 result = fjes_setup_resources(adapter);
228 if (result)
229 goto err_setup_res;
230
231 hw->txrx_stop_req_bit = 0;
232 hw->epstop_req_bit = 0;
233
234 fjes_hw_capture_interrupt_status(hw);
235
236 result = fjes_request_irq(adapter);
237 if (result)
238 goto err_req_irq;
239
240 fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, false);
241
242 netif_tx_start_all_queues(netdev);
243 netif_carrier_on(netdev);
244
245 return 0;
246
247err_req_irq:
248 fjes_free_irq(adapter);
249
250err_setup_res:
251 fjes_free_resources(adapter);
252 return result;
253}
254
255/* fjes_close - Disables a network interface */
256static int fjes_close(struct net_device *netdev)
257{
258 struct fjes_adapter *adapter = netdev_priv(netdev);
259 struct fjes_hw *hw = &adapter->hw;
260 int epidx;
261
262 netif_tx_stop_all_queues(netdev);
263 netif_carrier_off(netdev);
264
265 fjes_hw_raise_epstop(hw);
266
267 for (epidx = 0; epidx < hw->max_epid; epidx++) {
268 if (epidx == hw->my_epid)
269 continue;
270
271 adapter->hw.ep_shm_info[epidx].tx.info->v1i.rx_status &=
272 ~FJES_RX_POLL_WORK;
273 }
274
275 fjes_free_irq(adapter);
276
277 fjes_hw_wait_epstop(hw);
278
279 fjes_free_resources(adapter);
280
281 return 0;
282}
283
284static int fjes_setup_resources(struct fjes_adapter *adapter)
285{
286 struct net_device *netdev = adapter->netdev;
287 struct ep_share_mem_info *buf_pair;
288 struct fjes_hw *hw = &adapter->hw;
289 int result;
290 int epidx;
291
292 mutex_lock(&hw->hw_info.lock);
293 result = fjes_hw_request_info(hw);
294 switch (result) {
295 case 0:
296 for (epidx = 0; epidx < hw->max_epid; epidx++) {
297 hw->ep_shm_info[epidx].es_status =
298 hw->hw_info.res_buf->info.info[epidx].es_status;
299 hw->ep_shm_info[epidx].zone =
300 hw->hw_info.res_buf->info.info[epidx].zone;
301 }
302 break;
303 default:
304 case -ENOMSG:
305 case -EBUSY:
306 adapter->force_reset = true;
307
308 mutex_unlock(&hw->hw_info.lock);
309 return result;
310 }
311 mutex_unlock(&hw->hw_info.lock);
312
313 for (epidx = 0; epidx < (hw->max_epid); epidx++) {
314 if ((epidx != hw->my_epid) &&
315 (hw->ep_shm_info[epidx].es_status ==
316 FJES_ZONING_STATUS_ENABLE)) {
317 fjes_hw_raise_interrupt(hw, epidx,
318 REG_ICTL_MASK_INFO_UPDATE);
319 }
320 }
321
322 msleep(FJES_OPEN_ZONE_UPDATE_WAIT * hw->max_epid);
323
324 for (epidx = 0; epidx < (hw->max_epid); epidx++) {
325 if (epidx == hw->my_epid)
326 continue;
327
328 buf_pair = &hw->ep_shm_info[epidx];
329
330 fjes_hw_setup_epbuf(&buf_pair->tx, netdev->dev_addr,
331 netdev->mtu);
332
333 if (fjes_hw_epid_is_same_zone(hw, epidx)) {
334 mutex_lock(&hw->hw_info.lock);
335 result =
336 fjes_hw_register_buff_addr(hw, epidx, buf_pair);
337 mutex_unlock(&hw->hw_info.lock);
338
339 switch (result) {
340 case 0:
341 break;
342 case -ENOMSG:
343 case -EBUSY:
344 default:
345 adapter->force_reset = true;
346 return result;
347 }
348 }
349 }
350
351 return 0;
352}
353
354static void fjes_free_resources(struct fjes_adapter *adapter)
355{
356 struct net_device *netdev = adapter->netdev;
357 struct fjes_device_command_param param;
358 struct ep_share_mem_info *buf_pair;
359 struct fjes_hw *hw = &adapter->hw;
360 bool reset_flag = false;
361 int result;
362 int epidx;
363
364 for (epidx = 0; epidx < hw->max_epid; epidx++) {
365 if (epidx == hw->my_epid)
366 continue;
367
368 mutex_lock(&hw->hw_info.lock);
369 result = fjes_hw_unregister_buff_addr(hw, epidx);
370 mutex_unlock(&hw->hw_info.lock);
371
372 if (result)
373 reset_flag = true;
374
375 buf_pair = &hw->ep_shm_info[epidx];
376
377 fjes_hw_setup_epbuf(&buf_pair->tx,
378 netdev->dev_addr, netdev->mtu);
379
380 clear_bit(epidx, &hw->txrx_stop_req_bit);
381 }
382
383 if (reset_flag || adapter->force_reset) {
384 result = fjes_hw_reset(hw);
385
386 adapter->force_reset = false;
387
388 if (result)
389 adapter->open_guard = true;
390
391 hw->hw_info.buffer_share_bit = 0;
392
393 memset((void *)&param, 0, sizeof(param));
394
395 param.req_len = hw->hw_info.req_buf_size;
396 param.req_start = __pa(hw->hw_info.req_buf);
397 param.res_len = hw->hw_info.res_buf_size;
398 param.res_start = __pa(hw->hw_info.res_buf);
399 param.share_start = __pa(hw->hw_info.share->ep_status);
400
401 fjes_hw_init_command_registers(hw, &param);
402 }
403}
404
405static irqreturn_t fjes_intr(int irq, void *data)
406{
407 struct fjes_adapter *adapter = data;
408 struct fjes_hw *hw = &adapter->hw;
409 irqreturn_t ret;
410 u32 icr;
411
412 icr = fjes_hw_capture_interrupt_status(hw);
413
414 if (icr & REG_IS_MASK_IS_ASSERT)
415 ret = IRQ_HANDLED;
416 else
417 ret = IRQ_NONE;
418
419 return ret;
420}
421
176/* fjes_probe - Device Initialization Routine */ 422/* fjes_probe - Device Initialization Routine */
177static int fjes_probe(struct platform_device *plat_dev) 423static int fjes_probe(struct platform_device *plat_dev)
178{ 424{
diff --git a/drivers/net/fjes/fjes_regs.h b/drivers/net/fjes/fjes_regs.h
index cc975a0fd111..029c924dc175 100644
--- a/drivers/net/fjes/fjes_regs.h
+++ b/drivers/net/fjes/fjes_regs.h
@@ -49,8 +49,11 @@
49#define XSCT_RESPBAH 0x004C /* Response Buffer Address High */ 49#define XSCT_RESPBAH 0x004C /* Response Buffer Address High */
50 50
51/* Interrupt Control registers */ 51/* Interrupt Control registers */
52#define XSCT_IS 0x0080 /* Interrupt status */
52#define XSCT_IMS 0x0084 /* Interrupt mask set */ 53#define XSCT_IMS 0x0084 /* Interrupt mask set */
53#define XSCT_IMC 0x0088 /* Interrupt mask clear */ 54#define XSCT_IMC 0x0088 /* Interrupt mask clear */
55#define XSCT_IG 0x008C /* Interrupt generator */
56#define XSCT_ICTL 0x0090 /* Interrupt control */
54 57
55/* register structure */ 58/* register structure */
56/* Information registers */ 59/* Information registers */
@@ -101,6 +104,15 @@ union REG_CS {
101 __le32 reg; 104 __le32 reg;
102}; 105};
103 106
107/* Interrupt Control registers */
108union REG_ICTL {
109 struct {
110 __le32 automak:1;
111 __le32 rsv0:31;
112 } bits;
113 __le32 reg;
114};
115
104enum REG_ICTL_MASK { 116enum REG_ICTL_MASK {
105 REG_ICTL_MASK_INFO_UPDATE = 1 << 20, 117 REG_ICTL_MASK_INFO_UPDATE = 1 << 20,
106 REG_ICTL_MASK_DEV_STOP_REQ = 1 << 19, 118 REG_ICTL_MASK_DEV_STOP_REQ = 1 << 19,
@@ -110,6 +122,11 @@ enum REG_ICTL_MASK {
110 REG_ICTL_MASK_ALL = GENMASK(20, 16), 122 REG_ICTL_MASK_ALL = GENMASK(20, 16),
111}; 123};
112 124
125enum REG_IS_MASK {
126 REG_IS_MASK_IS_ASSERT = 1 << 31,
127 REG_IS_MASK_EPID = GENMASK(15, 0),
128};
129
113struct fjes_hw; 130struct fjes_hw;
114 131
115u32 fjes_hw_rd32(struct fjes_hw *hw, u32 reg); 132u32 fjes_hw_rd32(struct fjes_hw *hw, u32 reg);