barrier() 编译屏障是为了防止编译器对代码优化时,改变代码的先后顺序;
内存屏障( rmb() / wmb() )是让CPU对代码顺序执行。
下面举例barrier()在linux内核中的使用
1. 确保先获取omap->buf_len 的值,然后在omap_i2c_write_reg 中使用omap->buf_len,顺序不能变
omap->buf_len = msg->len;
/* make sure writes to omap->buf_len are ordered */
barrier();
omap_i2c_write_reg(omap, OMAP_I2C_CNT_REG, omap->buf_len);
2. 确保先更新dbell的值,然后在writel中使用dbell的值,顺序不能变
void qedf_ring_doorbell(struct qedf_rport *fcport)
{
struct fcoe_db_data dbell = { 0 };
dbell.agg_flags = 0;
dbell.params |= DB_DEST_XCM << FCOE_DB_DATA_DEST_SHIFT;
dbell.params |= DB_AGG_CMD_SET << FCOE_DB_DATA_AGG_CMD_SHIFT;
dbell.params |= DQ_XCM_FCOE_SQ_PROD_CMD <<
FCOE_DB_DATA_AGG_VAL_SEL_SHIFT;
dbell.sq_prod = fcport->fw_sq_prod_idx;
/* wmb makes sure that the BDs data is updated before updating the
* producer, otherwise FW may read old data from the BDs.
*/
wmb();
barrier();
writel(*(u32 *)&dbell, fcport->p_doorbell);
/*
* Fence required to flush the write combined buffer, since another
* CPU may write to the same doorbell address and data may be lost
* due to relaxed order nature of write combined bar.
*/
wmb();
}
3. 对外设写的顺序有要求,确保写的先后顺序,下面为先写高位,后写低位
/* make sure write the uaddr at the end */
barrier();
iowrite32((u32)(uaddr >> 32), qhead + offsetof(struct receive_queue, q_used_hi));
barrier();
iowrite32((u32)uaddr, qhead + offsetof(struct receive_queue, q_used_lo));